Admin improvements
This commit is contained in:
parent
d4b162426b
commit
9e55d27d33
@ -40,7 +40,9 @@
|
||||
dlg.removeAttribute('aria-hidden');
|
||||
dlg.setAttribute('role', 'alertdialog');
|
||||
dlg.setAttribute('tabindex', '0');
|
||||
dlg.focus();
|
||||
if (!dlg.getAttribute('data-nofocus')) {
|
||||
dlg.focus();
|
||||
}
|
||||
setTimeout(function() { dlg.classList.add('open'); }, 100);
|
||||
}
|
||||
window.closeOverlay = function(dlg, primaryContent, body) {
|
||||
@ -114,6 +116,14 @@
|
||||
return false;
|
||||
});
|
||||
});
|
||||
var helpDlg = document.getElementById('help-dlg');
|
||||
forEachElement('[data-help-text]', function(link) {
|
||||
link.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
openDlg(helpDlg, link);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
var loginDlg = document.getElementById('login-dlg');
|
||||
forEachElement('[data-sign-in]', function(link) {
|
||||
link.addEventListener('click', function(event) {
|
||||
|
@ -1,168 +1,200 @@
|
||||
(function() {
|
||||
var searchControl = document.getElementById('search');
|
||||
var searchControl = document.getElementById('search');
|
||||
|
||||
function filterTable() {
|
||||
forEach(document.getElementById('search-table').getElementsByTagName('TBODY')[0].getElementsByTagName('TR'), function(tr) {
|
||||
if (tr.classList.contains('editable')) {
|
||||
tr.classList.remove('hidden');
|
||||
function filterTable() {
|
||||
forEach(document.getElementById('search-table').getElementsByTagName('TBODY')[0].getElementsByTagName('TR'), function(tr) {
|
||||
if (tr.classList.contains('editable')) {
|
||||
tr.classList.remove('hidden');
|
||||
|
||||
var value = searchControl.value;
|
||||
if (value) {
|
||||
var words = value.split(/\s+/);
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
var word = new RegExp(words[i].replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), "i");
|
||||
if (tr.innerHTML.search(word) == -1) {
|
||||
tr.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
var value = searchControl.value;
|
||||
if (value) {
|
||||
var words = value.split(/\s+/);
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
var word = new RegExp(words[i].replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), "i");
|
||||
if (tr.innerHTML.search(word) == -1) {
|
||||
tr.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ref = https://davidwalsh.name/element-matches-selector
|
||||
function selectorMatches(el, selector) {
|
||||
var p = Element.prototype;
|
||||
var f = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || function(s) {
|
||||
return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
|
||||
};
|
||||
return f.call(el, selector);
|
||||
}
|
||||
// ref = https://davidwalsh.name/element-matches-selector
|
||||
function selectorMatches(el, selector) {
|
||||
if (el instanceof Element) {
|
||||
var p = Element.prototype;
|
||||
var f = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || function(s) {
|
||||
return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
|
||||
};
|
||||
return f.call(el, selector);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function saveRow(row) {
|
||||
if (row) {
|
||||
row.classList.remove('editing');
|
||||
var table = row.parentElement.parentElement;
|
||||
var editRow = row.nextSibling;
|
||||
var url = table.getAttribute('data-update-url');
|
||||
var data = new FormData();
|
||||
var request = new XMLHttpRequest();
|
||||
request.onreadystatechange = function() {
|
||||
if (request.readyState == 4) {
|
||||
row.classList.remove('requesting');
|
||||
if (request.status == 200 && request.responseText) {
|
||||
var tempTable = document.createElement('table');
|
||||
tempTable.innerHTML = request.responseText;
|
||||
var rows = tempTable.getElementsByTagName('tr');
|
||||
row.innerHTML = rows[0].innerHTML;
|
||||
editRow.innerHTML = rows[1].innerHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
request.open('POST', url, true);
|
||||
cells = editRow.getElementsByClassName('cell-editor');
|
||||
data.append('key', row.getAttribute('data-key'));
|
||||
data.append('button', 'update');
|
||||
var changed = false;
|
||||
for (var i = 0; i < cells.length; i++) {
|
||||
if (cells[i].value !== cells[i].getAttribute('data-value')) {
|
||||
data.append(cells[i].getAttribute('name'), cells[i].value);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
row.classList.add('requesting');
|
||||
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||||
request.send(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
function saveRow(row) {
|
||||
if (row) {
|
||||
row.classList.remove('editing');
|
||||
var table = row.parentElement.parentElement;
|
||||
var editRow = row.nextSibling;
|
||||
var url = table.getAttribute('data-update-url');
|
||||
var data = new FormData();
|
||||
var request = new XMLHttpRequest();
|
||||
request.onreadystatechange = function() {
|
||||
if (request.readyState == 4) {
|
||||
row.classList.remove('requesting');
|
||||
if (request.status == 200 && request.responseText) {
|
||||
var tempTable = document.createElement('table');
|
||||
tempTable.innerHTML = request.responseText;
|
||||
var rows = tempTable.getElementsByTagName('tr');
|
||||
row.innerHTML = rows[0].innerHTML;
|
||||
editRow.innerHTML = rows[1].innerHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
request.open('POST', url, true);
|
||||
cells = editRow.getElementsByClassName('cell-editor');
|
||||
data.append('key', row.getAttribute('data-key'));
|
||||
data.append('button', 'update');
|
||||
var changed = false;
|
||||
for (var i = 0; i < cells.length; i++) {
|
||||
if (cells[i].value !== cells[i].getAttribute('data-value')) {
|
||||
data.append(cells[i].getAttribute('name'), cells[i].value);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
row.classList.add('requesting');
|
||||
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||||
request.send(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function editTableCell(cell) {
|
||||
if (cell && selectorMatches(cell, 'tr[data-key].editable td')) {
|
||||
editTableRow(cell.parentElement, cell);
|
||||
} else if (!cell || !selectorMatches(cell, 'tr[data-key].editable + tr, tr[data-key].editable + tr *')) {
|
||||
var currentRow = document.querySelector('tr[data-key].editable.editing');
|
||||
if (currentRow) {
|
||||
saveRow(currentRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
function editTableRow(row, cell) {
|
||||
if (selectorMatches(row, 'tr[data-key].editable')) {
|
||||
var key = row.getAttribute('data-key');
|
||||
var currentRow = document.querySelector('tr[data-key].editable.editing');
|
||||
if (currentRow && currentRow.getAttribute('data-key') !== key) {
|
||||
saveRow(currentRow);
|
||||
}
|
||||
var editor = row.nextSibling;
|
||||
if (!row.classList.contains('editing')) {
|
||||
row.classList.add('editing');
|
||||
var focusElement = null;
|
||||
if (cell) {
|
||||
focusElement = editor.querySelector('td[data-column-id="' + cell.getAttribute('data-column-id') + '"] .cell-editor');
|
||||
}
|
||||
focusElement = focusElement || editor.getElementsByClassName('cell-editor')[0];
|
||||
focusElement.focus();
|
||||
if (focusElement.tagName === 'TEXTAREA' || (focusElement.tagName === 'INPUT' && focusElement.type != 'number' && focusElement.type != 'email')) {
|
||||
focusElement.setSelectionRange(0, focusElement.value.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
document.addEventListener('click', function (event) { editTableCell(event.target); });
|
||||
document.addEventListener('keyup', function (event) {
|
||||
if (event.code === "Enter") {
|
||||
var currentRow = document.querySelector('tr[data-key].editable.editing');
|
||||
if (currentRow) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
var next = event.shiftKey ? 'previousSibling' : 'nextSibling';
|
||||
var cell = document.activeElement.parentElement.getAttribute('data-column-id');
|
||||
var row = currentRow[next] ? currentRow[next][next] : null;
|
||||
if (!row) {
|
||||
rows = currentRow.parentElement.children;
|
||||
row = event.shiftKey ? rows[rows.length - 2] : rows[0];
|
||||
}
|
||||
editTableRow(row, row.querySelector('[data-column-id="' + cell + '"]'));
|
||||
}
|
||||
} else if (event.code === "Escape") {
|
||||
var currentRow = document.querySelector('tr[data-key].editable.editing');
|
||||
if (currentRow) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
saveRow(currentRow);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (document.observe) {
|
||||
document.observe("focusin", function (event) { editTableCell(event.target); });
|
||||
} else {
|
||||
document.addEventListener("focus", function (event) { editTableCell(event.target); }, true);
|
||||
}
|
||||
function sortBy(table, column, dir) {
|
||||
if (!dir) {
|
||||
dir = 'down';
|
||||
} else if (dir == 'down') {
|
||||
dir = 'up';
|
||||
} else {
|
||||
dir = 'down';
|
||||
}
|
||||
|
||||
window.onbeforeunload = function() {
|
||||
editTableCell();
|
||||
};
|
||||
var url = table.getAttribute('data-sort-url') + '?sort_column=' + column + '&sort_dir=' + dir;
|
||||
var tableContainer = table.parentElement;
|
||||
|
||||
searchControl.addEventListener('keyup', filterTable);
|
||||
searchControl.addEventListener('search', filterTable);
|
||||
tableContainer.classList.add('requesting');
|
||||
var request = new XMLHttpRequest();
|
||||
request.onreadystatechange = function() {
|
||||
if (request.readyState == 4) {
|
||||
tableContainer.classList.remove('requesting');
|
||||
if (request.status == 200 && request.responseText) {
|
||||
tableContainer.innerHTML = request.responseText;
|
||||
}
|
||||
}
|
||||
}
|
||||
request.open('GET', url, true);
|
||||
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||||
request.send();
|
||||
}
|
||||
|
||||
forEachElement('[data-expands]', function(button) {
|
||||
button.addEventListener('click', function(event) {
|
||||
var element = document.getElementById(event.target.getAttribute('data-expands'));
|
||||
document.body.classList.add('expanded-element');
|
||||
element.classList.add('expanded');
|
||||
});
|
||||
});
|
||||
forEachElement('[data-contracts]', function(button) {
|
||||
button.addEventListener('click', function(event) {
|
||||
var element = document.getElementById(event.target.getAttribute('data-contracts'));
|
||||
document.body.classList.remove('expanded-element');
|
||||
element.classList.remove('expanded');
|
||||
});
|
||||
});
|
||||
forEachElement('[data-opens-modal]', function(button) {
|
||||
button.addEventListener('click', function(event) {
|
||||
var element = document.getElementById(event.target.getAttribute('data-opens-modal'));
|
||||
document.body.classList.add('modal-open');
|
||||
element.classList.add('open');
|
||||
});
|
||||
});
|
||||
forEachElement('[data-closes-modal]', function(element) {
|
||||
element.addEventListener('click', function(event) {
|
||||
document.getElementById(event.target.getAttribute('data-closes-modal')).classList.remove('open');
|
||||
document.body.classList.remove('modal-open');
|
||||
});
|
||||
});
|
||||
function editTableCell(cell) {
|
||||
if (cell && selectorMatches(cell, 'tr[data-key].editable td')) {
|
||||
editTableRow(cell.parentElement, cell);
|
||||
} else if (cell && selectorMatches(cell, 'th[data-colname]')) {
|
||||
sortBy(cell.parentElement.parentElement.parentElement, cell.getAttribute('data-colname'), cell.getAttribute('data-dir'));
|
||||
} else if (!cell || !selectorMatches(cell, 'tr[data-key].editable + tr, tr[data-key].editable + tr *')) {
|
||||
var currentRow = document.querySelector('tr[data-key].editable.editing');
|
||||
if (currentRow) {
|
||||
saveRow(currentRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
function editTableRow(row, cell) {
|
||||
if (selectorMatches(row, 'tr[data-key].editable')) {
|
||||
var key = row.getAttribute('data-key');
|
||||
var currentRow = document.querySelector('tr[data-key].editable.editing');
|
||||
if (currentRow && currentRow.getAttribute('data-key') !== key) {
|
||||
saveRow(currentRow);
|
||||
}
|
||||
var editor = row.nextSibling;
|
||||
if (!row.classList.contains('editing')) {
|
||||
row.classList.add('editing');
|
||||
var focusElement = null;
|
||||
if (cell) {
|
||||
focusElement = editor.querySelector('td[data-column-id="' + cell.getAttribute('data-column-id') + '"] .cell-editor');
|
||||
}
|
||||
focusElement = focusElement || editor.getElementsByClassName('cell-editor')[0];
|
||||
focusElement.focus();
|
||||
if (focusElement.tagName === 'TEXTAREA' || (focusElement.tagName === 'INPUT' && focusElement.type != 'number' && focusElement.type != 'email')) {
|
||||
focusElement.setSelectionRange(0, focusElement.value.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
document.addEventListener('click', function (event) { editTableCell(event.target); });
|
||||
document.addEventListener('keyup', function (event) {
|
||||
if (event.code === "Enter") {
|
||||
var currentRow = document.querySelector('tr[data-key].editable.editing');
|
||||
if (currentRow) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
var next = event.shiftKey ? 'previousSibling' : 'nextSibling';
|
||||
var cell = document.activeElement.parentElement.getAttribute('data-column-id');
|
||||
var row = currentRow[next] ? currentRow[next][next] : null;
|
||||
if (!row) {
|
||||
rows = currentRow.parentElement.children;
|
||||
row = event.shiftKey ? rows[rows.length - 2] : rows[0];
|
||||
}
|
||||
editTableRow(row, row.querySelector('[data-column-id="' + cell + '"]'));
|
||||
}
|
||||
} else if (event.code === "Escape") {
|
||||
var currentRow = document.querySelector('tr[data-key].editable.editing');
|
||||
if (currentRow) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
saveRow(currentRow);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (document.observe) {
|
||||
document.observe("focusin", function (event) { editTableCell(event.target); });
|
||||
} else {
|
||||
document.addEventListener("focus", function (event) { editTableCell(event.target); }, true);
|
||||
}
|
||||
|
||||
window.onbeforeunload = function() {
|
||||
editTableCell();
|
||||
};
|
||||
|
||||
searchControl.addEventListener('keyup', filterTable);
|
||||
searchControl.addEventListener('search', filterTable);
|
||||
|
||||
forEachElement('[data-expands]', function(button) {
|
||||
button.addEventListener('click', function(event) {
|
||||
var element = document.getElementById(event.target.getAttribute('data-expands'));
|
||||
document.body.classList.add('expanded-element');
|
||||
element.classList.add('expanded');
|
||||
});
|
||||
});
|
||||
forEachElement('[data-contracts]', function(button) {
|
||||
button.addEventListener('click', function(event) {
|
||||
var element = document.getElementById(event.target.getAttribute('data-contracts'));
|
||||
document.body.classList.remove('expanded-element');
|
||||
element.classList.remove('expanded');
|
||||
});
|
||||
});
|
||||
forEachElement('[data-opens-modal]', function(button) {
|
||||
button.addEventListener('click', function(event) {
|
||||
var element = document.getElementById(event.target.getAttribute('data-opens-modal'));
|
||||
document.body.classList.add('modal-open');
|
||||
element.classList.add('open');
|
||||
});
|
||||
});
|
||||
forEachElement('[data-closes-modal]', function(element) {
|
||||
element.addEventListener('click', function(event) {
|
||||
document.getElementById(event.target.getAttribute('data-closes-modal')).classList.remove('open');
|
||||
document.body.classList.remove('modal-open');
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
@ -29,6 +29,61 @@ nav.sub-nav {
|
||||
}
|
||||
|
||||
table, .table {
|
||||
tr.spacer td {
|
||||
border: 0;
|
||||
height: 0.5em;
|
||||
}
|
||||
|
||||
&[data-sort-url] {
|
||||
[data-colname] {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
|
||||
@include after {
|
||||
content: 'ꜜ';
|
||||
position: absolute;
|
||||
bottom: -1em;
|
||||
left: 50%;
|
||||
font-size: 1.5em;
|
||||
opacity: 0;
|
||||
z-index: 2;
|
||||
margin-left: -0.25em;
|
||||
pointer-events: none;
|
||||
@include _(transition, opacity 150ms ease-in-out);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@include after {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[data-dir] {
|
||||
@include after {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@include after {
|
||||
content: 'ꜛ';
|
||||
}
|
||||
}
|
||||
}
|
||||
[data-dir="up"] {
|
||||
@include after {
|
||||
content: 'ꜛ';
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@include after {
|
||||
content: 'ꜜ';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
th, td, .table-th, .table-td {
|
||||
&.center {
|
||||
text-align: center;
|
||||
@ -51,45 +106,50 @@ table, .table {
|
||||
width: 1.75em;
|
||||
|
||||
&.happy {
|
||||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 87.8 73.2'><polygon fill='#{$colour-5}' points='34.3 73.2 0 32.6 18.7 16.8 35.4 36.5 70.1 0 87.8 16.8 '/></svg>");
|
||||
@include after {
|
||||
content: '\1F601';
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
&.unhappy {
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path xmlns="http://www.w3.org/2000/svg" d="M50 5C25.1 5 5 25.1 5 50c0 24.9 20.1 45 45 45s45-20.1 45-45C95 25.1 74.9 5 50 5zM72.5 64.3l-8.2 8.2L50 58.2 35.7 72.5l-8.2-8.2L41.8 50 27.5 35.7l8.2-8.2L50 41.8l14.3-14.3 8.2 8.2L58.2 50 72.5 64.3z" fill="#{$colour-4}"/></svg>');
|
||||
@include after {
|
||||
content: '\1F621';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
td, .table-td {
|
||||
&.inner-table {
|
||||
padding: 0;
|
||||
padding: 0.5em;
|
||||
|
||||
table {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
tr:first-child {
|
||||
td, th {
|
||||
border-top: 0;
|
||||
}
|
||||
}
|
||||
// tr:first-child {
|
||||
// td, th {
|
||||
// border-top: 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
tr:last-child {
|
||||
td, th {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
// tr:last-child {
|
||||
// td, th {
|
||||
// border-bottom: 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
td, th {
|
||||
&:first-child {
|
||||
border-left: 0
|
||||
}
|
||||
// td, th {
|
||||
// &:first-child {
|
||||
// border-left: 0
|
||||
// }
|
||||
|
||||
&:last-child {
|
||||
border-right: 0
|
||||
}
|
||||
}
|
||||
// &:last-child {
|
||||
// border-right: 0
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
&.bold {
|
||||
@ -359,6 +419,7 @@ body.expanded-element {
|
||||
z-index: 1002;
|
||||
background-color: #F8F8F8;
|
||||
flex: 1;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
.actions {
|
||||
@ -636,6 +697,12 @@ nav.sub-menu {
|
||||
}
|
||||
}
|
||||
|
||||
#registrations-table {
|
||||
.button {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#main article #registration-admin-menu {
|
||||
margin: 1em 0 0;
|
||||
padding: 0;
|
||||
@ -745,6 +812,15 @@ nav.sub-menu {
|
||||
}
|
||||
}
|
||||
|
||||
@include keyframes(unhappy) {
|
||||
from {
|
||||
@include _(transform, rotate(15deg));
|
||||
}
|
||||
to {
|
||||
@include _(transform, rotate(-15deg));
|
||||
}
|
||||
}
|
||||
|
||||
#admin-housing, #admin-schedule {
|
||||
.guests-housed {
|
||||
margin-bottom: 1em;
|
||||
@ -759,12 +835,33 @@ nav.sub-menu {
|
||||
.data {
|
||||
display: inline-block;
|
||||
font-size: 1.125em;
|
||||
|
||||
@include after {
|
||||
margin-left: 0.5em;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
&.happy {
|
||||
@include after {
|
||||
content: '\1F60D';
|
||||
}
|
||||
}
|
||||
|
||||
&.unhappy {
|
||||
@include after {
|
||||
content: '\1F61E';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#housing-table {
|
||||
@include _(transition, opacity 1s ease-in-out);
|
||||
|
||||
table {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&.loading {
|
||||
@include _(opacity, 0.5);
|
||||
pointer-events: none;
|
||||
@ -780,6 +877,10 @@ nav.sub-menu {
|
||||
text-align: right;
|
||||
@include font-family(primary);
|
||||
}
|
||||
|
||||
.name {
|
||||
min-width: 10em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -788,28 +889,17 @@ nav.sub-menu {
|
||||
td {
|
||||
background-color: lighten($colour-1, 40%);
|
||||
|
||||
&:hover {
|
||||
background-color: $colour-1;
|
||||
}
|
||||
|
||||
&.full {
|
||||
background-color: $gray;
|
||||
|
||||
&:hover {
|
||||
background-color: #CCC;
|
||||
}
|
||||
.button {
|
||||
background-color: #888;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
color: $white;
|
||||
text-align: center;
|
||||
@include font-family(secondary);
|
||||
|
||||
@include after {
|
||||
display: none;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
@ -819,15 +909,31 @@ nav.sub-menu {
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.state {
|
||||
position: relative;
|
||||
font-family: inherit;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
|
||||
@include after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
&.unhappy {
|
||||
cursor: pointer;
|
||||
|
||||
@include after {
|
||||
@include _(transform-origin, bottom);
|
||||
@include _(animation, unhappy ease-in-out 1s infinite alternate both);
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
@ -837,7 +943,7 @@ nav.sub-menu {
|
||||
top: 0;
|
||||
background-color: $white;
|
||||
border: 0.1em solid #CCC;
|
||||
padding: 0.25em 0.75em 0.25em 1.5em;
|
||||
padding: 0.25em 0.75em;
|
||||
margin: 0;
|
||||
list-style-type: square;
|
||||
@include default-box-shadow(top, 2);
|
||||
@ -846,7 +952,12 @@ nav.sub-menu {
|
||||
|
||||
li {
|
||||
white-space: nowrap;
|
||||
margin: 0;
|
||||
margin: 0 0 0 1em;
|
||||
|
||||
&:first-child:last-child {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@ -893,25 +1004,71 @@ nav.sub-menu {
|
||||
background-color: $white;
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
padding: 1em;
|
||||
height: 80%;
|
||||
cursor: default;
|
||||
@include default-box-shadow(top, 2);
|
||||
|
||||
h3 {
|
||||
text-align: center;
|
||||
margin: 0 0 1em;
|
||||
padding: 0.5em 0.6667em;
|
||||
color: $white;
|
||||
background-color: $green;
|
||||
@include _(text-stroke, 1px rgba(0, 0, 0, 0.25));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-scroller.no-edit {
|
||||
box-shadow: none;
|
||||
background-color: transparent;
|
||||
|
||||
table {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#table, #help-dlg {
|
||||
.legend ul {
|
||||
@include _-(display, flex);
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
@include _(flex, 1);
|
||||
text-align: center;
|
||||
margin-bottom: 0.5em;
|
||||
padding: 0.125em 0.5em;
|
||||
margin: 0.1em;
|
||||
border: 0.1em solid $light-gray;
|
||||
background-color: #F8F8F8;
|
||||
@include font-family(secondary);
|
||||
|
||||
&.other-host, &.other-space, &.bad-match {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&.selected-space, &.other-space {
|
||||
background-color: $colour-5;
|
||||
}
|
||||
|
||||
&.other-host {
|
||||
background-color: $colour-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#table {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
height: 80%;
|
||||
height: calc(100% - 4em);
|
||||
height: calc(100% - 6.5em);
|
||||
background-color: $white;
|
||||
margin: 1em;
|
||||
@include _(transition, background-color 250ms ease-in-out);
|
||||
|
||||
&.loading {
|
||||
@ -924,7 +1081,7 @@ nav.sub-menu {
|
||||
}
|
||||
|
||||
table {
|
||||
margin: 0 0 2em;
|
||||
margin: 0 0 1em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
@ -992,45 +1149,27 @@ nav.sub-menu {
|
||||
}
|
||||
}
|
||||
|
||||
.legend ul {
|
||||
@include _-(display, flex);
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
@include _(flex, 1);
|
||||
text-align: center;
|
||||
margin-bottom: 0.5em;
|
||||
padding: 0.125em 0.5em;
|
||||
margin: 0.1em;
|
||||
border: 0.1em solid $light-gray;
|
||||
background-color: #F8F8F8;
|
||||
@include font-family(secondary);
|
||||
|
||||
&.other-host, &.other-space, &.bad-match {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&.selected-space, &.other-space {
|
||||
background-color: $colour-5;
|
||||
}
|
||||
|
||||
&.other-host {
|
||||
background-color: $colour-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.p {
|
||||
max-height: 4em;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.guest-table {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
td, th {
|
||||
white-space: nowrap;
|
||||
|
||||
&.break-ok {
|
||||
white-space: normal;
|
||||
min-width: 10em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#admin-housing {
|
||||
#table table {
|
||||
min-width: 100em;
|
||||
}
|
||||
|
||||
#hosts {
|
||||
background-color: $white;
|
||||
|
@ -141,21 +141,6 @@ table, .table {
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
&.state {
|
||||
background-size: 1.333em;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
width: 1.75em;
|
||||
|
||||
&.happy {
|
||||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 87.8 73.2'><polygon fill='#{$colour-5}' points='34.3 73.2 0 32.6 18.7 16.8 35.4 36.5 70.1 0 87.8 16.8 '/></svg>");
|
||||
}
|
||||
|
||||
&.unhappy {
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path xmlns="http://www.w3.org/2000/svg" d="M50 5C25.1 5 5 25.1 5 50c0 24.9 20.1 45 45 45s45-20.1 45-45C95 25.1 74.9 5 50 5zM72.5 64.3l-8.2 8.2L50 58.2 35.7 72.5l-8.2-8.2L41.8 50 27.5 35.7l8.2-8.2L50 41.8l14.3-14.3 8.2 8.2L58.2 50 72.5 64.3z" fill="#{$colour-4}"/></svg>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
th, .table-th {
|
||||
@ -167,42 +152,42 @@ table, .table {
|
||||
}
|
||||
}
|
||||
|
||||
td, .table-td {
|
||||
&.inner-table {
|
||||
padding: 0;
|
||||
// td, .table-td {
|
||||
// &.inner-table {
|
||||
// padding: 0;
|
||||
|
||||
table {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
// table {
|
||||
// margin: 0;
|
||||
// width: 100%;
|
||||
// }
|
||||
|
||||
tr:first-child {
|
||||
td, th {
|
||||
border-top: 0;
|
||||
}
|
||||
}
|
||||
// tr:first-child {
|
||||
// td, th {
|
||||
// border-top: 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
tr:last-child {
|
||||
td, th {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
// tr:last-child {
|
||||
// td, th {
|
||||
// border-bottom: 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
td, th {
|
||||
&:first-child {
|
||||
border-left: 0
|
||||
}
|
||||
// td, th {
|
||||
// &:first-child {
|
||||
// border-left: 0
|
||||
// }
|
||||
|
||||
&:last-child {
|
||||
border-right: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
// &:last-child {
|
||||
// border-right: 0
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
&.bold {
|
||||
@include font-family(secondary);
|
||||
}
|
||||
}
|
||||
// &.bold {
|
||||
// @include font-family(secondary);
|
||||
// }
|
||||
// }
|
||||
|
||||
tbody th {
|
||||
width: 0.1rem;
|
||||
@ -2449,13 +2434,14 @@ a.logo {
|
||||
.register-link {
|
||||
font-size: 1.25em;
|
||||
margin: 0.5em;
|
||||
|
||||
.button {
|
||||
@include _(animation, radiate 2s linear infinite alternate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.help-link {
|
||||
float: right;
|
||||
background-color: $red;
|
||||
}
|
||||
|
||||
.conference-details {
|
||||
.links {
|
||||
text-align: center;
|
||||
@ -2906,6 +2892,29 @@ body {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#help-dlg {
|
||||
.dlg-content {
|
||||
@include _-(display, flex);
|
||||
@include _(flex-direction, column);
|
||||
max-width: 60rem;
|
||||
}
|
||||
|
||||
.dlg-inner {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.title {
|
||||
background-color: $red;
|
||||
font-size: 2em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.message {
|
||||
text-align: left;
|
||||
font-size: 1.125em;
|
||||
}
|
||||
}
|
||||
|
||||
#info-dlg .message {
|
||||
text-align: left;
|
||||
|
||||
@ -2956,10 +2965,6 @@ body {
|
||||
to { background-position: 60px 30px; }
|
||||
}
|
||||
|
||||
@include keyframes(radiate) {
|
||||
to { background-color: $green; }
|
||||
}
|
||||
|
||||
html :focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
"and_chr": ["59"],
|
||||
"chrome": ["59"],
|
||||
"edge": ["13"],
|
||||
"firefox": ["50"],
|
||||
"firefox": ["52"],
|
||||
"ie": ["11"],
|
||||
"ios_saf": ["8", "9"]
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
require 'geocoder/calculations'
|
||||
require 'rest_client'
|
||||
require 'registration_controller_helper'
|
||||
|
||||
class ConferenceAdministrationController < ApplicationController
|
||||
include RegistrationControllerHelper
|
||||
|
||||
def administration
|
||||
set_conference
|
||||
return do_403 unless @this_conference.host? current_user
|
||||
@ -224,6 +227,47 @@ class ConferenceAdministrationController < ApplicationController
|
||||
return respond_to do |format|
|
||||
format.xlsx { render xlsx: '../conferences/stats', filename: "stats-#{DateTime.now.strftime('%Y-%m-%d')}" }
|
||||
end
|
||||
else
|
||||
if params[:sort_column]
|
||||
col = params[:sort_column].to_sym
|
||||
@excel_data[:data].sort_by! do |row|
|
||||
value = row[col]
|
||||
|
||||
if row[:raw_values].key?(col)
|
||||
value = if row[:raw_values][col].is_a?(TrueClass)
|
||||
't'
|
||||
elsif row[:raw_values][col].is_a?(FalseClass)
|
||||
''
|
||||
else
|
||||
row[:raw_values][col]
|
||||
end
|
||||
elsif value.is_a?(City)
|
||||
value = value.sortable_string
|
||||
end
|
||||
|
||||
if value.nil?
|
||||
case @excel_data[:column_types][col]
|
||||
when :datetime, [:date, :day]
|
||||
value = Date.new
|
||||
when :money
|
||||
value = 0
|
||||
else
|
||||
value = ''
|
||||
end
|
||||
end
|
||||
|
||||
value
|
||||
end
|
||||
|
||||
if params[:sort_dir] == 'up'
|
||||
@sort_dir = :up
|
||||
@excel_data[:data].reverse!
|
||||
end
|
||||
|
||||
@sort_column = col
|
||||
else
|
||||
@sort_column = :name
|
||||
end
|
||||
end
|
||||
|
||||
@registration_count = @registrations.size
|
||||
@ -249,6 +293,10 @@ class ConferenceAdministrationController < ApplicationController
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if request.xhr?
|
||||
render html: view_context.html_table(@excel_data, view_context.registrations_table_options)
|
||||
end
|
||||
end
|
||||
|
||||
def administrate_stats
|
||||
@ -372,6 +420,7 @@ class ConferenceAdministrationController < ApplicationController
|
||||
return respond_to do |format|
|
||||
format.xlsx { render xlsx: '../conferences/stats', filename: "housing" }
|
||||
end
|
||||
else
|
||||
end
|
||||
end
|
||||
|
||||
@ -428,16 +477,21 @@ class ConferenceAdministrationController < ApplicationController
|
||||
columns: [
|
||||
:name,
|
||||
:email,
|
||||
:date,
|
||||
:status,
|
||||
:is_attending,
|
||||
:is_subscribed,
|
||||
:registration_fees_paid,
|
||||
:date,
|
||||
:payment_currency,
|
||||
:payment_method,
|
||||
:city,
|
||||
:preferred_language
|
||||
] +
|
||||
User.AVAILABLE_LANGUAGES.map { |l| "language_#{l}".to_sym } +
|
||||
[
|
||||
[
|
||||
:group_ride,
|
||||
:organization,
|
||||
:org_non_member_interest,
|
||||
:arrival,
|
||||
:departure,
|
||||
:housing,
|
||||
@ -451,8 +505,7 @@ class ConferenceAdministrationController < ApplicationController
|
||||
:last_day,
|
||||
:address,
|
||||
:phone
|
||||
] + ConferenceRegistration.all_spaces +
|
||||
ConferenceRegistration.all_considerations + [
|
||||
] + ConferenceRegistration.all_spaces + [
|
||||
:notes
|
||||
],
|
||||
column_types: {
|
||||
@ -460,6 +513,7 @@ class ConferenceAdministrationController < ApplicationController
|
||||
date: :datetime,
|
||||
email: :email,
|
||||
companion_email: :email,
|
||||
org_non_member_interest: :text,
|
||||
arrival: [:date, :day],
|
||||
departure: [:date, :day],
|
||||
registration_fees_paid: :money,
|
||||
@ -476,6 +530,9 @@ class ConferenceAdministrationController < ApplicationController
|
||||
is_subscribed: 'articles.user_settings.headings.email_subscribe',
|
||||
city: 'forms.labels.generic.event_location',
|
||||
date: 'articles.conference_registration.terms.Date',
|
||||
group_ride: 'articles.conference_registration.step_names.group_ride',
|
||||
organization: 'articles.conference_registration.step_names.org_select',
|
||||
org_non_member_interest: 'articles.conference_registration.step_names.org_non_member_interest',
|
||||
preferred_language: 'articles.conference_registration.terms.Preferred_Languages',
|
||||
arrival: 'forms.labels.generic.arrival',
|
||||
departure: 'forms.labels.generic.departure',
|
||||
@ -485,13 +542,15 @@ class ConferenceAdministrationController < ApplicationController
|
||||
companion: 'articles.conference_registration.terms.companion',
|
||||
companion_email: 'articles.conference_registration.terms.companion_email',
|
||||
registration_fees_paid: 'articles.conference_registration.headings.fees_paid',
|
||||
payment_currency: 'forms.labels.generic.payment_currency',
|
||||
payment_method: 'forms.labels.generic.payment_method',
|
||||
other: 'forms.labels.generic.other_notes',
|
||||
can_provide_housing: 'articles.conference_registration.can_provide_housing',
|
||||
can_provide_housing: 'articles.conference_registration.housing_provider',
|
||||
first_day: 'forms.labels.generic.first_day',
|
||||
last_day: 'forms.labels.generic.last_day',
|
||||
notes: 'forms.labels.generic.notes',
|
||||
phone: 'forms.labels.generic.phone',
|
||||
address: 'forms.labels.generic.address',
|
||||
address: 'forms.labels.generic.address_short',
|
||||
contact_info: 'articles.conference_registration.headings.contact_info',
|
||||
questions: 'articles.conference_registration.headings.questions',
|
||||
hosting: 'articles.conference_registration.headings.hosting'
|
||||
@ -504,7 +563,7 @@ class ConferenceAdministrationController < ApplicationController
|
||||
end
|
||||
|
||||
User.AVAILABLE_LANGUAGES.each do |l|
|
||||
@excel_data[:keys]["language_#{l}".to_sym] = "languages.#{l.to_s}"
|
||||
@excel_data[:keys]["language_#{l}".to_sym] = "languages.#{l.to_s}"
|
||||
end
|
||||
ConferenceRegistration.all_spaces.each do |s|
|
||||
@excel_data[:column_types][s] = :number
|
||||
@ -517,41 +576,51 @@ class ConferenceAdministrationController < ApplicationController
|
||||
user = r.user_id ? User.where(id: r.user_id).first : nil
|
||||
if user.present?
|
||||
companion = view_context.companion(r)
|
||||
companion = companion.is_a?(User) ? companion.name : (view_context._"articles.conference_registration.terms.registration_status.#{companion}") if companion.present?
|
||||
companion = companion.is_a?(User) ? companion.name : I18n.t("articles.conference_registration.terms.registration_status.#{companion}") if companion.present?
|
||||
steps = r.steps_completed || []
|
||||
|
||||
if id.nil? || id == r.id
|
||||
registration_data = r.data || {}
|
||||
housing_data = r.housing_data || {}
|
||||
availability = housing_data['availability'] || []
|
||||
availability[0] = Date.parse(availability[0]) if availability[0].present?
|
||||
availability[1] = Date.parse(availability[1]) if availability[1].present?
|
||||
org = r.user.organizations.first
|
||||
|
||||
data = {
|
||||
id: r.id,
|
||||
name: user.firstname || '',
|
||||
email: user.email || '',
|
||||
status: (view_context._"articles.conference_registration.terms.registration_status.#{view_context.registration_status(r)}"),
|
||||
is_attending: (view_context._"articles.conference_registration.questions.bike.#{r.is_attending == 'n' ? 'no' : 'yes'}"),
|
||||
is_subscribed: user.is_subscribed == false ? (view_context._'articles.conference_registration.questions.bike.no') : '',
|
||||
status: I18n.t("articles.conference_registration.terms.registration_status.#{view_context.registration_status(r)}"),
|
||||
is_attending: I18n.t("articles.conference_registration.questions.bike.#{r.is_attending == 'n' ? 'no' : 'yes'}"),
|
||||
is_subscribed: user.is_subscribed == false ? I18n.t('articles.conference_registration.questions.bike.no') : '',
|
||||
date: r.created_at ? r.created_at.strftime("%F %T") : '',
|
||||
city: r.city || '',
|
||||
preferred_language: user.locale.present? ? (view_context.language_name user.locale) : '',
|
||||
arrival: r.arrival ? r.arrival.strftime("%F %T") : '',
|
||||
departure: r.departure ? r.departure.strftime("%F %T") : '',
|
||||
housing: r.housing.present? ? (view_context._"articles.conference_registration.questions.housing.#{r.housing}") : '',
|
||||
bike: r.bike.present? ? (view_context._"articles.conference_registration.questions.bike.#{r.bike}") : '',
|
||||
food: r.food.present? ? (view_context._"articles.conference_registration.questions.food.#{r.food}") : '',
|
||||
group_ride: registration_data['group_ride'].present? ? I18n.t("forms.actions.generic.#{registration_data['group_ride']}") : '',
|
||||
organization: org.present? ? org.name : '',
|
||||
org_non_member_interest: registration_data['non_member_interest'],
|
||||
housing: r.housing.present? ? I18n.t("articles.conference_registration.questions.housing_short.#{r.housing}") : '',
|
||||
bike: r.bike.present? ? I18n.t("articles.conference_registration.questions.bike.#{r.bike}") : '',
|
||||
food: r.food.present? ? I18n.t("articles.conference_registration.questions.food.#{r.food}") : '',
|
||||
companion: companion,
|
||||
companion_email: (housing_data['companion'] || { 'email' => ''})['email'],
|
||||
registration_fees_paid: r.registration_fees_paid,
|
||||
other: r.allergies.present? ? "#{r.allergies}\n\n#{r.other}" : r.other,
|
||||
can_provide_housing: r.can_provide_housing ? (view_context._'articles.conference_registration.questions.bike.yes') : '',
|
||||
registration_fees_paid: registration_data['payment_amount'],
|
||||
payment_currency: registration_data['payment_currency'],
|
||||
payment_method: registration_data['payment_method'].present? ? I18n.t("forms.labels.generic.payment_type.#{registration_data['payment_method']}") : '',
|
||||
other: [r.allergies, r.other, housing_data['other']].compact.join("\n\n"),
|
||||
can_provide_housing: r.can_provide_housing.nil? ? '' : I18n.t("articles.conference_registration.questions.bike.#{r.can_provide_housing ? 'yes' : 'no'}"),
|
||||
first_day: availability[0].present? ? availability[0].strftime("%F %T") : '',
|
||||
last_day: availability[1].present? ? availability[1].strftime("%F %T") : '',
|
||||
notes: housing_data['notes'],
|
||||
address: housing_data['address'],
|
||||
phone: housing_data['phone'],
|
||||
raw_values: {
|
||||
group_ride: registration_data['group_ride'],
|
||||
registration_fees_paid: registration_data['payment_amount'].to_f,
|
||||
payment_method: registration_data['payment_method'],
|
||||
housing: r.housing,
|
||||
bike: r.bike,
|
||||
food: r.food,
|
||||
@ -560,12 +629,13 @@ class ConferenceAdministrationController < ApplicationController
|
||||
preferred_language: user.locale,
|
||||
is_attending: r.is_attending != 'n',
|
||||
is_subscribed: user.is_subscribed,
|
||||
can_provide_housing: r.can_provide_housing,
|
||||
can_provide_housing: r.can_provide_housing.to_s,
|
||||
first_day: availability[0].present? ? availability[0].to_date : nil,
|
||||
last_day: availability[1].present? ? availability[1].to_date : nil
|
||||
},
|
||||
html_values: {
|
||||
date: r.created_at.present? ? r.created_at.strftime("%F %T") : '',
|
||||
registration_fees_paid: registration_data['payment_amount'].present? ? view_context.number_to_currency(registration_data['payment_amount'].to_f, unit: '$') : '',
|
||||
arrival: r.arrival.present? ? view_context.date(r.arrival.to_date, :span_same_year_date_1) : '',
|
||||
departure: r.departure.present? ? view_context.date(r.departure.to_date, :span_same_year_date_1) : '',
|
||||
first_day: availability[0].present? ? view_context.date(availability[0].to_date, :span_same_year_date_1) : '',
|
||||
@ -574,17 +644,13 @@ class ConferenceAdministrationController < ApplicationController
|
||||
}
|
||||
User.AVAILABLE_LANGUAGES.each do |l|
|
||||
can_speak = ((user.languages || []).include? l.to_s)
|
||||
data["language_#{l}".to_sym] = (can_speak ? (view_context._'articles.conference_registration.questions.bike.yes') : '')
|
||||
data["language_#{l}".to_sym] = (can_speak ? I18n.t('articles.conference_registration.questions.bike.yes') : '')
|
||||
data[:raw_values]["language_#{l}".to_sym] = can_speak
|
||||
end
|
||||
ConferenceRegistration.all_spaces.each do |s|
|
||||
space = (housing_data['space'] || {})[s.to_s]
|
||||
data[s] = space.present? ? space.to_i : nil
|
||||
end
|
||||
ConferenceRegistration.all_considerations.each do |c|
|
||||
consideration = (housing_data['considerations'] || []).include?(c.to_s)
|
||||
data[c] = (consideration ? (view_context._'articles.conference_registration.questions.bike.yes') : '')
|
||||
data[:raw_values][c] = consideration
|
||||
data[:raw_values][s] = space.present? ? space.to_i : 0
|
||||
end
|
||||
@excel_data[:data] << data
|
||||
end
|
||||
@ -593,18 +659,18 @@ class ConferenceAdministrationController < ApplicationController
|
||||
|
||||
if html_format
|
||||
yes_no = [
|
||||
[(view_context._"articles.conference_registration.questions.bike.yes"), true],
|
||||
[(view_context._"articles.conference_registration.questions.bike.no"), false]
|
||||
[I18n.t('forms.actions.generic.yes'), true],
|
||||
[I18n.t('forms.actions.generic.no'), false]
|
||||
]
|
||||
@column_options = {
|
||||
housing: ConferenceRegistration.all_housing_options.map { |h| [
|
||||
(view_context._"articles.conference_registration.questions.housing.#{h}"),
|
||||
I18n.t("articles.conference_registration.questions.housing_short.#{h}"),
|
||||
h] },
|
||||
bike: ConferenceRegistration.all_bike_options.map { |b| [
|
||||
(view_context._"articles.conference_registration.questions.bike.#{b}"),
|
||||
I18n.t("articles.conference_registration.questions.bike.#{b}"),
|
||||
b] },
|
||||
food: ConferenceRegistration.all_food_options.map { |f| [
|
||||
(view_context._"articles.conference_registration.questions.food.#{f}"),
|
||||
I18n.t("articles.conference_registration.questions.food.#{f}"),
|
||||
f] },
|
||||
arrival: view_context.conference_days_options_list(:before_plus_one),
|
||||
departure: view_context.conference_days_options_list(:after_minus_one),
|
||||
@ -615,16 +681,19 @@ class ConferenceAdministrationController < ApplicationController
|
||||
is_subscribed: [yes_no.last],
|
||||
can_provide_housing: yes_no,
|
||||
first_day: view_context.conference_days_options_list(:before),
|
||||
last_day: view_context.conference_days_options_list(:after)
|
||||
last_day: view_context.conference_days_options_list(:after),
|
||||
group_ride: [:yes, :no, :maybe].map { |o| [I18n.t("forms.actions.generic.#{o}"), o] },
|
||||
payment_currency: Conference.default_currencies.map { |c| [c, c] },
|
||||
payment_method: ConferenceRegistration.all_payment_methods.map { |c| [I18n.t("forms.labels.generic.payment_type.#{c}"), c] }
|
||||
}
|
||||
User.AVAILABLE_LANGUAGES.each do |l|
|
||||
@column_options["language_#{l}".to_sym] = [
|
||||
[(view_context._"articles.conference_registration.questions.bike.yes"), true]
|
||||
[I18n.t("articles.conference_registration.questions.bike.yes"), true]
|
||||
]
|
||||
end
|
||||
ConferenceRegistration.all_considerations.each do |c|
|
||||
@column_options[c.to_sym] = [
|
||||
[(view_context._"articles.conference_registration.questions.bike.yes"), true]
|
||||
[I18n.t("articles.conference_registration.questions.bike.yes"), true]
|
||||
]
|
||||
end
|
||||
end
|
||||
@ -633,7 +702,7 @@ class ConferenceAdministrationController < ApplicationController
|
||||
def get_housing_data
|
||||
@hosts = {}
|
||||
@guests = {}
|
||||
ConferenceRegistration.where(:conference_id => @this_conference.id).each do |registration|
|
||||
ConferenceRegistration.where(conference_id: @this_conference.id).each do |registration|
|
||||
if registration.can_provide_housing
|
||||
@hosts[registration.id] = registration
|
||||
elsif registration.housing.present? && registration.housing != 'none'
|
||||
@ -657,6 +726,7 @@ class ConferenceAdministrationController < ApplicationController
|
||||
@housing_data[id][:space][s.to_sym] = size
|
||||
end
|
||||
end
|
||||
@unhappy_people = Set.new
|
||||
|
||||
@guests_housed = 0
|
||||
|
||||
@ -691,7 +761,7 @@ class ConferenceAdministrationController < ApplicationController
|
||||
|
||||
if (guest.housing == 'house' && space == :tent) ||
|
||||
(guest.housing == 'tent' && (space == :bed_space || space == :floor_space))
|
||||
@housing_data[host_id][:guest_data][guest_id][:warnings][:space] = { actual: (view_context._"forms.labels.generic.#{space.to_s}"), expected: (view_context._"articles.conference_registration.questions.housing.#{guest.housing}")}
|
||||
@housing_data[host_id][:guest_data][guest_id][:warnings][:space] = { actual: (view_context._"forms.labels.generic.#{space.to_s}"), expected: (view_context._"articles.conference_registration.questions.housing_short.#{guest.housing}")}
|
||||
end
|
||||
|
||||
if data['companion'].present?
|
||||
@ -717,6 +787,7 @@ class ConferenceAdministrationController < ApplicationController
|
||||
end
|
||||
end
|
||||
end
|
||||
@unhappy_people << guest_id if @housing_data[host_id][:guest_data][guest_id][:errors].present? || @housing_data[host_id][:guest_data][guest_id][:warnings].present?
|
||||
else
|
||||
# make sure the housing data is empty if the host wasn't found, just in case something happened to the host
|
||||
@guests[guest_id].housing_data ||= {}
|
||||
@ -739,6 +810,7 @@ class ConferenceAdministrationController < ApplicationController
|
||||
|
||||
if @housing_data[id][:guests][space].size > space_available
|
||||
@housing_data[id][:warnings][:space][space] << :overbooked
|
||||
@unhappy_people << id
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1021,12 +1093,22 @@ class ConferenceAdministrationController < ApplicationController
|
||||
registration.city_id = city.id
|
||||
end
|
||||
end
|
||||
when :housing, :bike, :food, :allergies, :other
|
||||
registration.send("#{key.to_s}=", value)
|
||||
when :housing, :bike, :food
|
||||
registration.send("#{key}=", value)
|
||||
when :other
|
||||
registration.housing_data ||= {}
|
||||
registration.housing_data[key] = value
|
||||
# delete deprecated values
|
||||
registration.allergies = nil
|
||||
registration.other = nil
|
||||
when :registration_fees_paid
|
||||
registration.registration_fees_paid = value.to_i
|
||||
registration.data ||= {}
|
||||
registration.data['payment_amount'] = value.to_f
|
||||
when :group_ride, :payment_currency, :payment_method
|
||||
registration.data ||= {}
|
||||
registration.data[key.to_s] = value.present? ? value.to_sym : nil
|
||||
when :can_provide_housing
|
||||
registration.send("#{key.to_s}=", value.present?)
|
||||
registration.send("#{key.to_s}=", value == 'true' ? true : (value == 'false' ? false : nil))
|
||||
when :arrival, :departure
|
||||
registration.send("#{key.to_s}=", value.present? ? Date.parse(value) : nil)
|
||||
when :companion_email
|
||||
|
@ -160,21 +160,6 @@ module AdminHelper
|
||||
end
|
||||
end
|
||||
|
||||
# housing_data = guest.housing_data || []
|
||||
|
||||
# if housing_data['host'].present?
|
||||
# if housing_data['host'] == host.id
|
||||
# return space == housing_data['space'] ? :selected_space : :other_space
|
||||
# end
|
||||
|
||||
# return :other_host
|
||||
# end
|
||||
|
||||
# if space_matches?(space, guest.housing) && available_dates_match?(host, guest)
|
||||
# return :good_match
|
||||
# end
|
||||
|
||||
# return :bad_match
|
||||
return :good_match
|
||||
end
|
||||
|
||||
@ -190,6 +175,7 @@ module AdminHelper
|
||||
|
||||
def available_dates_match?(host, guest)
|
||||
return false unless host.housing_data['availability'].present? && host.housing_data['availability'][1].present?
|
||||
return false unless guest.arrival.present? && guest.departure.present?
|
||||
if host.housing_data['availability'][0] <= guest.arrival &&
|
||||
host.housing_data['availability'][1] >= guest.departure
|
||||
return true
|
||||
@ -208,4 +194,10 @@ module AdminHelper
|
||||
end).html_safe
|
||||
end).html_safe
|
||||
end
|
||||
|
||||
def admin_help_pages
|
||||
return {
|
||||
housing: :housing
|
||||
}
|
||||
end
|
||||
end
|
||||
|
@ -74,7 +74,7 @@ module GeocoderHelper
|
||||
return nil unless city.present?
|
||||
|
||||
hash = Hash.new
|
||||
region_translation = region.present? && country.present? ? _("geography.subregions.#{country}.#{region}", locale: locale) : ''
|
||||
region_translation = region.present? && country.present? ? I18n.t("geography.subregions.#{country}.#{region}", locale: locale, resolve: false) : ''
|
||||
country_translation = country.present? ? _("geography.countries.#{country}", locale: locale) : ''
|
||||
hash[:city] = _!(city) if city.present?
|
||||
hash[:region] = region_translation if region_translation.present?
|
||||
|
@ -8,6 +8,7 @@ module RegistrationHelper
|
||||
|
||||
def registration_status(registration)
|
||||
return :unregistered if registration.nil?
|
||||
return :cancelled if registration.is_attending == 'n'
|
||||
return registration.status
|
||||
end
|
||||
|
||||
@ -47,7 +48,7 @@ module RegistrationHelper
|
||||
completed_steps = registration.steps_completed || []
|
||||
last_step = nil
|
||||
steps = current_registration_steps(registration) || []
|
||||
steps.each do | step |
|
||||
steps.each do |step|
|
||||
# return the last enabled step if this one is disabled
|
||||
return last_step unless step[:enabled]
|
||||
|
||||
|
@ -1,7 +1,12 @@
|
||||
module TableHelper
|
||||
def html_edit_table(excel_data, options = {})
|
||||
attributes = { class: options[:class], id: options[:id] }
|
||||
attributes[:data] = { 'update-url' => options[:editable] } if options[:editable].present?
|
||||
if options[:editable].present? || options[:sortable].present?
|
||||
attributes[:data] = {
|
||||
'update-url' => options[:editable],
|
||||
'sort-url' => options[:sortable]
|
||||
}
|
||||
end
|
||||
|
||||
if options[:column_names].is_a? Hash
|
||||
return content_tag(:table, attributes) do
|
||||
@ -9,11 +14,11 @@ module TableHelper
|
||||
column_names = {}
|
||||
(content_tag(:thead) do
|
||||
headers = ''
|
||||
options[:column_names].each do | header_name, columns |
|
||||
options[:column_names].each do |header_name, columns|
|
||||
column_names[header_name] ||= []
|
||||
headers += content_tag(:th, excel_data[:keys][header_name].present? ? _(excel_data[:keys][header_name]) : '', colspan: 2)
|
||||
row_count = columns.size
|
||||
columns.each do | column |
|
||||
columns.each do |column|
|
||||
column_names[header_name] << column
|
||||
if (options[:row_spans] || {})[column].present?
|
||||
row_count += (options[:row_spans][column] - 1)
|
||||
@ -30,15 +35,18 @@ module TableHelper
|
||||
|
||||
for i in 0...max_columns
|
||||
columns_html = ''
|
||||
column_names.each do | header_name, columns |
|
||||
column_names.each do |header_name, columns|
|
||||
column = columns[i]
|
||||
if column.present?
|
||||
attributes = { class: [excel_data[:column_types][column]], data: { 'column-id' => column } }
|
||||
if (options[:row_spans] || {})[column].present?
|
||||
attributes[:rowspan] = options[:row_spans][column]
|
||||
end
|
||||
columns_html += content_tag(:th, excel_data[:keys][column].present? ? _(excel_data[:keys][column]) : '', rowspan: attributes[:rowspan]) +
|
||||
edit_column(nil, column, nil, attributes, excel_data, options)
|
||||
|
||||
column_text = excel_data[:keys][column].present? ? _(excel_data[:keys][column]) : ''
|
||||
|
||||
columns_html += content_tag(:th, column_text.html_safe, rowspan: attributes[:rowspan]) +
|
||||
edit_column(nil, column, nil, attributes, excel_data, options)
|
||||
elsif column != false
|
||||
columns_html += content_tag(:td, ' ', colspan: 2, class: :empty)
|
||||
end
|
||||
@ -56,8 +64,9 @@ module TableHelper
|
||||
if (excel_data[:column_types] || {})[column] != :table && ((options[:column_names] || []).include? column)
|
||||
rows += content_tag(:tr, { class: 'always-edit', data: { key: '' } }) do
|
||||
attributes = { class: [excel_data[:column_types][column]], data: { 'column-id' => column } }
|
||||
columns = content_tag(:th, excel_data[:keys][column].present? ? _(excel_data[:keys][column]) : '') +
|
||||
edit_column(nil, column, nil, attributes, excel_data, options)
|
||||
column_text = excel_data[:keys][column].present? ? _(excel_data[:keys][column]) : ''
|
||||
|
||||
columns = content_tag(:th, column_text.html_safe) + edit_column(nil, column, nil, attributes, excel_data, options)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -70,7 +79,16 @@ module TableHelper
|
||||
def html_table(excel_data, options = {})
|
||||
options[:html] = true
|
||||
attributes = { class: options[:class], id: options[:id] }
|
||||
attributes[:data] = { 'update-url' => options[:editable] } if options[:editable].present?
|
||||
|
||||
if options[:editable].present?
|
||||
attributes[:data] ||= {}
|
||||
attributes[:data]['update-url'] = options[:editable]
|
||||
end
|
||||
if options[:sortable].present?
|
||||
attributes[:data] ||= {}
|
||||
attributes[:data]['sort-url'] = options[:sortable]
|
||||
end
|
||||
|
||||
content_tag(:table, attributes) do
|
||||
(content_tag(:thead) do
|
||||
content_tag(:tr, excel_header_columns(excel_data))
|
||||
@ -106,7 +124,17 @@ module TableHelper
|
||||
|
||||
data[:columns].each do |column|
|
||||
unless data[:column_types].present? && data[:column_types][column] == :table
|
||||
columns += content_tag(:th, data[:keys][column].present? ? _(data[:keys][column]) : '', class: class_name)
|
||||
column_text = data[:keys][column].present? ? _(data[:keys][column]) : ''
|
||||
attrs = { class: class_name }
|
||||
|
||||
unless @sort_column.nil?
|
||||
attrs[:data] = { colname: column }
|
||||
|
||||
if @sort_column == column
|
||||
attrs[:data][:dir] = @sort_dir || :down
|
||||
end
|
||||
end
|
||||
columns += content_tag(:th, column_text.html_safe, attrs)
|
||||
end
|
||||
end
|
||||
|
||||
@ -214,7 +242,7 @@ module TableHelper
|
||||
|
||||
def edit_column(row, column, value, attributes, data, options)
|
||||
attributes[:class] << 'has-editor'
|
||||
raw_value = row.present? ? (row[:raw_values][column] || value) : nil
|
||||
raw_value = row.present? ? ((row[:raw_values] || {})[column] || value) : nil
|
||||
|
||||
if row.present? && options[:html] && row[:html_values].present? && row[:html_values][column].present?
|
||||
value = row[:html_values][column]
|
||||
@ -299,14 +327,16 @@ module TableHelper
|
||||
] + User.AVAILABLE_LANGUAGES.map { |l| "language_#{l}".to_sym },
|
||||
questions: [
|
||||
:registration_fees_paid,
|
||||
:payment_currency,
|
||||
:payment_method,
|
||||
:is_attending,
|
||||
:arrival,
|
||||
:departure,
|
||||
:housing,
|
||||
:bike,
|
||||
:food,
|
||||
:group_ride,
|
||||
:companion_email,
|
||||
:allergies,
|
||||
:other
|
||||
],
|
||||
hosting: [
|
||||
@ -315,14 +345,15 @@ module TableHelper
|
||||
:phone,
|
||||
:first_day,
|
||||
:last_day
|
||||
] + ConferenceRegistration.all_spaces +
|
||||
ConferenceRegistration.all_considerations + [
|
||||
] + ConferenceRegistration.all_spaces + [
|
||||
:notes
|
||||
]
|
||||
},
|
||||
row_spans: {
|
||||
allergies: 3,
|
||||
other: 2
|
||||
other: 2,
|
||||
address: 2,
|
||||
city: 2,
|
||||
notes: 4
|
||||
},
|
||||
required_columns: [:name, :email],
|
||||
editable: administration_update_path(@this_conference.slug, @admin_step),
|
||||
@ -337,12 +368,15 @@ module TableHelper
|
||||
primary_key: :id,
|
||||
column_names: [
|
||||
:registration_fees_paid,
|
||||
:payment_currency,
|
||||
:payment_method,
|
||||
:is_attending,
|
||||
:is_subscribed,
|
||||
:city,
|
||||
:preferred_language,
|
||||
:arrival,
|
||||
:departure,
|
||||
:group_ride,
|
||||
:housing,
|
||||
:bike,
|
||||
:food,
|
||||
@ -360,6 +394,7 @@ module TableHelper
|
||||
ConferenceRegistration.all_spaces +
|
||||
ConferenceRegistration.all_considerations,
|
||||
editable: administration_update_path(@this_conference.slug, @admin_step),
|
||||
sortable: administration_step_path(@this_conference.slug, @admin_step),
|
||||
column_options: @column_options
|
||||
}
|
||||
end
|
||||
|
@ -99,75 +99,86 @@ module WidgetsHelper
|
||||
def host_guests_table(registration)
|
||||
id = registration.id
|
||||
html = ''
|
||||
first_row = true
|
||||
|
||||
@housing_data[id][:guests].each do |area, guests|
|
||||
guest_rows = ''
|
||||
guests.each do |guest_id, guest|
|
||||
space_size = (@housing_data[id][:space][area] || 0)
|
||||
|
||||
if space_size > 0 || guests.size > 0
|
||||
guests.each do |guest_id, guest|
|
||||
status_html = ''
|
||||
|
||||
@housing_data[id][:guest_data][guest_id][:errors].each do |error, value|
|
||||
if value.is_a?(Array)
|
||||
value.each do |v|
|
||||
status_html += content_tag(:li, _("errors.messages.housing.space.#{error.to_s}", vars: v))
|
||||
end
|
||||
else
|
||||
status_html += content_tag(:li, _("errors.messages.housing.space.#{error.to_s}", vars: value))
|
||||
end
|
||||
end
|
||||
|
||||
@housing_data[id][:guest_data][guest_id][:warnings].each do |error, value|
|
||||
if value.is_a?(Array)
|
||||
value.each do |v|
|
||||
status_html += content_tag(:li, _("warnings.messages.housing.space.#{error.to_s}", v))
|
||||
end
|
||||
else
|
||||
status_html += content_tag(:li, _("warnings.messages.housing.space.#{error.to_s}", vars: value))
|
||||
end
|
||||
end
|
||||
|
||||
if status_html.present?
|
||||
status_html = content_tag(:ul, status_html.html_safe)
|
||||
end
|
||||
|
||||
guest_rows += content_tag :tr, id: "hosted-guest-#{guest_id}" do
|
||||
(content_tag :td, guest[:guest].user.name) +
|
||||
(content_tag :td do
|
||||
(guest[:guest].from +
|
||||
(content_tag :a, (_'actions.workshops.Remove'), href: '#', class: 'remove-guest', data: { guest: guest_id })).html_safe
|
||||
end) +
|
||||
(content_tag :td, status_html.html_safe, class: [:state, status_html.present? ? :unhappy : :happy])
|
||||
end
|
||||
end
|
||||
|
||||
# add empty rows to represent empty guest spots
|
||||
for i in guests.size...space_size
|
||||
guest_rows += content_tag :tr, class: 'empty-space' do
|
||||
(content_tag :td, ' '.html_safe, colspan: 2) +
|
||||
(content_tag :td)
|
||||
end
|
||||
end
|
||||
|
||||
status_html = ''
|
||||
|
||||
@housing_data[id][:guest_data][guest_id][:errors].each do |error, value|
|
||||
if value.is_a?(Array)
|
||||
value.each do |v|
|
||||
status_html += content_tag(:li, _("errors.messages.housing.space.#{error.to_s}", vars: v))
|
||||
end
|
||||
else
|
||||
status_html += content_tag(:li, _("errors.messages.housing.space.#{error.to_s}", vars: value))
|
||||
if @housing_data[id][:warnings].present? && @housing_data[id][:warnings][:space].present? && @housing_data[id][:warnings][:space][area].present?
|
||||
@housing_data[id][:warnings][:space][area].each do |w|
|
||||
status_html += content_tag(:li, _("warnings.messages.housing.space.#{w.to_s}"))
|
||||
end
|
||||
end
|
||||
|
||||
@housing_data[id][:guest_data][guest_id][:warnings].each do |error, value|
|
||||
if value.is_a?(Array)
|
||||
value.each do |v|
|
||||
status_html += content_tag(:li, _("warnings.messages.housing.space.#{error.to_s}", v))
|
||||
end
|
||||
else
|
||||
status_html += content_tag(:li, _("warnings.messages.housing.space.#{error.to_s}", vars: value))
|
||||
end
|
||||
end
|
||||
|
||||
if status_html.present?
|
||||
status_html = content_tag(:ul, status_html.html_safe)
|
||||
end
|
||||
|
||||
guest_rows += content_tag :tr, id: "hosted-guest-#{guest_id}" do
|
||||
(content_tag :td, guest[:guest].user.name) +
|
||||
(content_tag :td do
|
||||
(guest[:guest].from +
|
||||
(content_tag :a, (_'actions.workshops.Remove'), href: '#', class: 'remove-guest', data: { guest: guest_id })).html_safe
|
||||
end) +
|
||||
(content_tag :td, status_html.html_safe, class: [:state, status_html.present? ? :unhappy : :happy])
|
||||
unless first_row
|
||||
html += content_tag :tr, class: :spacer do
|
||||
content_tag :td, '', colspan: 3
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
space_size = (@housing_data[id][:space][area] || 0)
|
||||
|
||||
# add empty rows to represent empty guest spots
|
||||
for i in guests.size...space_size
|
||||
guest_rows += content_tag :tr, class: 'empty-space' do
|
||||
(content_tag :td, ' '.html_safe, colspan: 2) +
|
||||
(content_tag :td)
|
||||
html += content_tag :tr do
|
||||
(content_tag :th, (_"forms.labels.generic.#{area}"), colspan: 2) +
|
||||
(content_tag :th, status_html.html_safe, class: [:state, status_html.present? ? :unhappy : :happy])
|
||||
end
|
||||
end
|
||||
|
||||
status_html = ''
|
||||
if @housing_data[id][:warnings].present? && @housing_data[id][:warnings][:space].present? && @housing_data[id][:warnings][:space][area].present?
|
||||
@housing_data[id][:warnings][:space][area].each do |w|
|
||||
status_html += content_tag(:li, _("warnings.messages.housing.space.#{w.to_s}"))
|
||||
html += guest_rows
|
||||
html += content_tag :tr, class: 'place-guest' do
|
||||
content_tag :td, class: guests.size >= space_size ? 'full' : nil, colspan: 3 do
|
||||
content_tag :a, (_"forms.actions.generic.place_guest_in.#{area}"), class: 'select-guest button small', href: '#', data: { host: id, space: area }
|
||||
end
|
||||
end
|
||||
end
|
||||
if status_html.present?
|
||||
status_html = content_tag(:ul, status_html.html_safe)
|
||||
end
|
||||
|
||||
html += content_tag :tr do
|
||||
(content_tag :th, (_"forms.labels.generic.#{area}"), colspan: 2) +
|
||||
(content_tag :th, status_html.html_safe, class: [:state, status_html.present? ? :unhappy : :happy])
|
||||
end
|
||||
html += guest_rows
|
||||
html += content_tag :tr, class: 'place-guest' do
|
||||
content_tag :td, class: guests.size >= space_size ? 'full' : nil, colspan: 3 do
|
||||
content_tag :a, (_'forms.actions.generic.place_guest'), class: 'select-guest', href: '#', data: { host: id, space: area }
|
||||
end
|
||||
first_row = false
|
||||
end
|
||||
end
|
||||
|
||||
@ -181,21 +192,31 @@ module WidgetsHelper
|
||||
id = registration.id
|
||||
@housing_data[id][:guests].each do |area, guests|
|
||||
max_space = @housing_data[id][:space][area] || 0
|
||||
area_name = (_"forms.labels.generic.#{area}")
|
||||
status_html = ''
|
||||
if @housing_data[id][:warnings].present? && @housing_data[id][:warnings][:space].present? && @housing_data[id][:warnings][:space][area].present?
|
||||
@housing_data[id][:warnings][:space][area].each do |w|
|
||||
status_html += content_tag(:div, _("warnings.housing.space.#{w.to_s}"), class: 'warning')
|
||||
|
||||
# don't include the area if the host doesn't want anyone there
|
||||
if max_space > 0 || guests.size > 0
|
||||
area_name = (_"forms.labels.generic.#{area}")
|
||||
status_html = ''
|
||||
if @housing_data[id][:warnings].present? && @housing_data[id][:warnings][:space].present? && @housing_data[id][:warnings][:space][area].present?
|
||||
@housing_data[id][:warnings][:space][area].each do |w|
|
||||
status_html += content_tag(:div, _("warnings.housing.space.#{w.to_s}"), class: 'warning')
|
||||
end
|
||||
end
|
||||
space_html = content_tag(:h5, area_name + _!(" (#{guests.size.to_s}/#{max_space.to_s})") + status_html.html_safe)
|
||||
guest_items = ''
|
||||
guests.each do |guest_id, guest|
|
||||
guest_items += content_tag(:li, guest[:guest].user.name, id: "hosted-guest-#{guest_id}")
|
||||
end
|
||||
space_html += content_tag(:ul, guest_items.html_safe)
|
||||
|
||||
# see if the space is overbooked
|
||||
booked_state = guests.size >= max_space ? (guests.size > max_space ? :overbooked : :booked) : nil
|
||||
|
||||
# let space be overbooked, even bed space can be overbooked if a couple is staying in the bed
|
||||
space_html += button :place_guest, type: :button, value: "#{area}:#{id}", class: [:small, 'place-guest', 'on-top-only', booked_state, max_space > 0 ? nil : :unwanted]
|
||||
|
||||
html += content_tag(:div, space_html, class: [:space, area, max_space > 0 || guests.size > 0 ? nil : 'on-top-only'])
|
||||
end
|
||||
space_html = content_tag(:h5, area_name + _!(" (#{guests.size.to_s}/#{max_space.to_s})") + status_html.html_safe)
|
||||
guest_items = ''
|
||||
guests.each do |guest_id, guest|
|
||||
guest_items += content_tag(:li, guest[:guest].user.name, id: "hosted-guest-#{guest_id}")
|
||||
end
|
||||
space_html += content_tag(:ul, guest_items.html_safe)
|
||||
space_html += button :place_guest, type: :button, value: "#{area}:#{id}", class: [:small, 'place-guest', 'on-top-only', guests.size >= max_space ? (guests.size > max_space ? :overbooked : :booked) : nil, max_space > 0 ? nil : :unwanted]
|
||||
html += content_tag(:div, space_html, class: [:space, area, max_space > 0 || guests.size > 0 ? nil : 'on-top-only'])
|
||||
end
|
||||
|
||||
classes << 'status-warning' if @housing_data[id][:warnings].present?
|
||||
@ -228,6 +249,16 @@ module WidgetsHelper
|
||||
end
|
||||
end
|
||||
|
||||
def link_help_dlg(topic, args = {})
|
||||
@help_dlg ||= true
|
||||
args[:data] ||= {}
|
||||
args[:data]['info-title'] = I18n.t("help.headings.#{topic}")
|
||||
args[:data]['help-text'] = true
|
||||
content_tag(:a, args) do
|
||||
(I18n.t('help.link_text') + content_tag(:template, (render "/help/#{topic}"), class: 'message')).html_safe
|
||||
end
|
||||
end
|
||||
|
||||
def button_with_confirmation(button_name, confirmation_text = nil, args = {})
|
||||
if confirmation_text.is_a? Hash
|
||||
args = confirmation_text
|
||||
|
@ -7,10 +7,10 @@
|
||||
- if @conference.present? && (@conference.registration_status == :pre || @conference.registration_status == :open)
|
||||
%p=_'articles.user_settings.paragraphs.conference_registration', :t
|
||||
= link_to (_'actions.conference.edit_registration'), register_path(@conference.slug), class: :button
|
||||
- if @conferences.present?
|
||||
- if @my_conferences.present?
|
||||
%h3=_'articles.user_settings.headings.Your_Conferences'
|
||||
.link-dump
|
||||
- @conferences.each do | conference |
|
||||
- @my_conferences.each do |conference|
|
||||
= link_to (_!conference.title), administrate_conference_path(conference.slug), class: :button
|
||||
|
||||
= form_tag update_settings_path do
|
||||
|
@ -1,11 +1,20 @@
|
||||
.guests-housed
|
||||
%h5 Guests Housed:
|
||||
.data="#{@guests_housed} / #{@guests.size}"
|
||||
.data{class: @guests_housed < @guests.size ? :unhappy : :happy }="#{@guests_housed} / #{@guests.size}"
|
||||
- if @guests_housed > 0
|
||||
.guests-housed
|
||||
%h5 Unhappy hosts and guests:
|
||||
.data{class: @unhappy_people.size > 0 ? :unhappy : :happy }="#{@unhappy_people.size}"
|
||||
|
||||
- first_row = true
|
||||
%table.hosts.admin-edit
|
||||
- @hosts.each do | id, registration |
|
||||
- @hosts.each do |id, registration|
|
||||
- unless first_row
|
||||
%tr.spacer
|
||||
%td
|
||||
%tr.host
|
||||
%th
|
||||
.name=registration.user.name
|
||||
.address=registration.housing_data['address']
|
||||
%td.inner-table{colspan: 2}=host_guests_table(registration)
|
||||
- first_row = false
|
||||
|
@ -6,5 +6,5 @@
|
||||
= admin_update_form class: 'guest-dlg', id: 'guest-list-table' do
|
||||
%h3 Select a Guest
|
||||
#table
|
||||
.actions
|
||||
.actions.center
|
||||
= link_to (_'links.download.Excel'), administration_step_path(@this_conference.slug, @admin_step, :format => :xlsx), class: [:button, :download]
|
||||
|
@ -6,12 +6,12 @@
|
||||
%a.button{data: { expands: 'registrations-table' }}='expand'
|
||||
%a.button.delete{data: { contracts: 'registrations-table' }}='close'
|
||||
%a.button.modify{data: { 'opens-modal': 'new-registration' }}='+'
|
||||
.table-scroller
|
||||
= html_table @excel_data, registrations_table_options
|
||||
.table-scroller#registrations
|
||||
= html_table(@excel_data, registrations_table_options)
|
||||
= admin_update_form id: 'new-registration', class: 'modal-edit' do
|
||||
.modal-edit-overlay{data: { 'closes-modal': 'new-registration' }}
|
||||
.modal-edit-content
|
||||
= html_edit_table @excel_data, registrations_edit_table_options
|
||||
.actions.right
|
||||
%a.button.subdued{data: { 'closes-modal': 'new-registration' }}='Cancel'
|
||||
.actions.center
|
||||
%a.button.subdued{data: { 'closes-modal': 'new-registration' }} Cancel
|
||||
= button :save, value: :save, class: :modify
|
||||
|
@ -1,50 +1,54 @@
|
||||
= hidden_field_tag :host, host.id
|
||||
.host-field
|
||||
%h4.inline=_'forms.labels.generic.name'
|
||||
%span.plain-value= host.user.name
|
||||
.host-field
|
||||
%h4.inline=_'articles.conference_registration.headings.host.availability'
|
||||
%span.plain-value= host.housing_data['availability'].present? && host.housing_data['availability'][1].present? ? date_span(host.housing_data['availability'][0].to_date, host.housing_data['availability'][1].to_date) : ''
|
||||
- if host.housing_data['considerations'].present?
|
||||
.host-field
|
||||
%h4.inline=_'articles.conference_registration.headings.host.considerations'
|
||||
%span.plain-value= (host.housing_data['considerations'].map { | consideration | _"articles.conference_registration.host.considerations.#{consideration}" }).join(', ')
|
||||
- if sanitize(host.housing_data['notes'], tags: []).present?
|
||||
.host-field
|
||||
%h4=_'articles.conference_registration.headings.host.notes'
|
||||
%blockquote= host.housing_data['notes'].html_safe
|
||||
%table.guests.admin-edit
|
||||
%tr
|
||||
%th.corner
|
||||
%th=_'forms.labels.generic.organization'
|
||||
%th=_'forms.labels.generic.city'
|
||||
%th=_'forms.labels.generic.housing'
|
||||
%th=_'articles.admin.housing.headings.arrival_departure'
|
||||
%th=_'articles.conference_registration.headings.companion'
|
||||
%th=_'forms.labels.generic.food'
|
||||
%th=_'forms.labels.generic.other'
|
||||
- @guests.each do | id, registration |
|
||||
%tr.selectable{class: get_housing_match(host, registration, space).to_s.gsub('_', '-'), data: {host: host.id, guest: id, space: space}}
|
||||
%th=registration.user.name
|
||||
%td
|
||||
- if registration.user.organizations.present?
|
||||
= registration.user.organizations.first.name
|
||||
- else
|
||||
%em None
|
||||
%td=registration.city
|
||||
%td=registration.housing.present? ? (_"articles.conference_registration.questions.housing.#{registration.housing}") : ''
|
||||
%td=date_span(registration.arrival.to_date, registration.departure.to_date)
|
||||
- companion = companion(registration)
|
||||
%td=companion.present? ? (companion.is_a?(User) ? companion.named_email : (_"articles.conference_registration.terms.registration_status.#{companion}")) : ''
|
||||
%td=registration.food.present? ? (_"articles.conference_registration.questions.food.#{registration.food}") : ''
|
||||
%td
|
||||
.p=registration.other
|
||||
.host
|
||||
= hidden_field_tag :host, host.id
|
||||
%h4 Host
|
||||
.table-scroller.no-edit
|
||||
%table.guests.admin-edit
|
||||
%tr
|
||||
%th.corner
|
||||
%th=_'forms.labels.generic.hosting_space'
|
||||
%th=_'forms.labels.generic.first_day'
|
||||
%th=_'forms.labels.generic.last_day'
|
||||
%th=_'articles.conference_registration.headings.host.notes'
|
||||
%tr
|
||||
- availability = host.housing_data['availability']
|
||||
%th=host.user.name
|
||||
%td=_"forms.labels.generic.#{space}"
|
||||
%td=(availability || [])[0].present? ? availability[0].present? ? date(availability[0].to_date, :span_same_year_date_1) : '' : ''
|
||||
%td=(availability || [])[1].present? ? date(availability[1].to_date, :span_same_year_date_1) : ''
|
||||
%td=((host.housing_data || {})['notes'] || '').html_safe
|
||||
|
||||
.legend
|
||||
%h4 Legend
|
||||
%ul
|
||||
%li.good-match Good Match
|
||||
%li.bad-match Poor Match
|
||||
%li.selected-space Also in this space
|
||||
%li.other-space Also with this host
|
||||
%li.other-host Already hosted
|
||||
%h4 Guests
|
||||
.guest-table
|
||||
.table-scroller.no-edit
|
||||
%table.guests.admin-edit
|
||||
%tr
|
||||
%th.corner
|
||||
%th=_'forms.labels.generic.housing'
|
||||
%th=_'forms.labels.generic.arrival'
|
||||
%th=_'forms.labels.generic.departure'
|
||||
%th=_'forms.labels.generic.other_notes'
|
||||
%th=_'forms.labels.generic.city'
|
||||
%th=_'forms.labels.generic.organization'
|
||||
%th=_'articles.conference_registration.headings.companion'
|
||||
%th=_'forms.labels.generic.food'
|
||||
- @guests.each do |id, registration|
|
||||
%tr.selectable{class: get_housing_match(host, registration, space).to_s.gsub('_', '-'), data: {host: host.id, guest: id, space: space}}
|
||||
%th.break-ok=registration.user.name
|
||||
%td=registration.housing.present? ? (_"articles.conference_registration.questions.housing.#{registration.housing}") : ''
|
||||
%td
|
||||
- if registration.arrival.present?
|
||||
=date(registration.arrival.to_date, :span_same_year_date_1)
|
||||
%td
|
||||
- if registration.departure.present?
|
||||
=date(registration.departure.to_date, :span_same_year_date_1)
|
||||
%td.break-ok
|
||||
.p=[registration.allergies, registration.other, (registration.housing_data || {})['other']].compact.join("\n\n")
|
||||
%td=registration.city
|
||||
%td.break-ok
|
||||
- if registration.user.organizations.present?
|
||||
= registration.user.organizations.first.name
|
||||
- else
|
||||
%em None
|
||||
- companion = companion(registration)
|
||||
%td=companion.present? ? (companion.is_a?(User) ? companion.named_email : (_"articles.conference_registration.terms.registration_status.#{companion}")) : ''
|
||||
%td=registration.food.present? ? (_"articles.conference_registration.questions.food.#{registration.food}") : ''
|
||||
|
@ -1,7 +1,7 @@
|
||||
- body_class 'banner-bottom' unless @this_conference.poster.present?
|
||||
- add_stylesheet :admin
|
||||
- content_for :banner do
|
||||
= render :partial => 'application/header', :locals => { page_group: :administration, page_key: 'Administration', image_file: @this_conference.poster_url || 'admin.jpg'}
|
||||
= render partial: 'application/header', locals: { page_group: :administration, page_key: 'Administration', image_file: @this_conference.poster_url || 'admin.jpg'}
|
||||
|
||||
%article
|
||||
= row do
|
||||
@ -10,7 +10,7 @@
|
||||
%h2=@this_conference.title
|
||||
%p=_'articles.admin.paragraphs.administration', :p
|
||||
%ul.break
|
||||
- administration_steps.each do | step, actions |
|
||||
- administration_steps.each do |step, actions|
|
||||
%li
|
||||
.info
|
||||
%h3=_"articles.admin.#{step}.heading", :t
|
||||
@ -18,7 +18,7 @@
|
||||
%p=_"articles.admin.#{step}.description", :p
|
||||
|
||||
.actions.figures
|
||||
- actions.each do | action |
|
||||
- actions.each do |action|
|
||||
- action_text = (_"articles.admin.#{step}.headings.#{action}", :t)
|
||||
.figure
|
||||
= link_to administration_step_path(@this_conference.slug, action.to_s) do
|
||||
|
@ -1,11 +1,13 @@
|
||||
- body_class 'banner-bottom' unless @this_conference.poster.present?
|
||||
- add_stylesheet :admin
|
||||
- content_for :banner do
|
||||
= render :partial => 'application/header', :locals => { page_group: :administration, page_key: 'Administration', image_file: @this_conference.poster_url || 'admin.jpg'}
|
||||
= render partial: 'application/header', locals: { page_group: :administration, page_key: 'Administration', image_file: @this_conference.poster_url || 'admin.jpg'}
|
||||
|
||||
%article{id: "admin-#{@admin_step}"}
|
||||
= row do
|
||||
= columns(medium: 12) do
|
||||
- if admin_help_pages[@admin_step.to_sym]
|
||||
= link_help_dlg("admin_#{admin_help_pages[@admin_step.to_sym]}", class: ['button', 'help-link'])
|
||||
%h2.floating=(_"articles.admin.#{@admin_group}.headings.#{@admin_step}", :t)
|
||||
= row do
|
||||
= columns(medium: 12) do
|
||||
|
@ -1,14 +0,0 @@
|
||||
- page_name = 'All '+(@conference_type ? @conference_type.title+' ' : '')+' Conferences'
|
||||
- title page_name
|
||||
- banner_image '/assets/conference.jpg'
|
||||
- page_style :list
|
||||
- content_for :banner do
|
||||
.row
|
||||
.columns
|
||||
%h1=_'page.Conferences'
|
||||
|
||||
%h2=page_name
|
||||
|
||||
%ul.small-block-grid-1.medium-block-grid-2.large-block-grid-3.conference-list.preview-list
|
||||
- @conferences.each do |conference|
|
||||
%li=render 'preview', :conference => conference
|
31
app/views/help/_admin_housing.html.haml
Normal file
31
app/views/help/_admin_housing.html.haml
Normal file
@ -0,0 +1,31 @@
|
||||
%p On this page you will see a list of hosts (housing providers) each with a list of their open spaces, beds, floor space, and tent space.
|
||||
|
||||
%h3 How to match a guest with host
|
||||
|
||||
%p Find a host and select a space to place a guest in, then press the "Place a guest in..." button to add a guest to that area. Once you press that button a popup will appear showing you extended details on the host and a list of guests with details. Take a look at the notes section for both the host and the guest to determine if the two will make a good match but also pay attention to the colour of the row:
|
||||
|
||||
.legend
|
||||
%h4 Legend
|
||||
%ul
|
||||
%li.good-match Good Match
|
||||
%li.bad-match Poor Match
|
||||
%li.selected-space Also in this space
|
||||
%li.other-space Also with this host
|
||||
%li.other-host Already hosted
|
||||
|
||||
%h3 Dealing with poor matches
|
||||
|
||||
%p A poor match can happen for several reasons:
|
||||
%ul
|
||||
%li A host space may not be available for the entire time that a guest wishes to stay
|
||||
%li A guest may be placed in a space (bed, floor, or tent) which is not their preferred space
|
||||
%li A guest may be placed in a space without their companion
|
||||
%li A host may have more guests than they indicated as their maximum
|
||||
|
||||
%p When a match is likely good, you will see a 😁 beside their placement, when a match is poor you will see a 😡. If you see the unhappy face, you can hover over the face to show more details on why the guest or host is unhappy.
|
||||
|
||||
%p You may wish to remove the guest and fin a better placement but keep in mind that this will not always be possible. For example, often guests will ask to be placed with many other friends but arranging this can be difficult. Speak with guests and hosts if possible to arrange a compromise, it is generally encouraged that guests stay with new people as long as they feel safe.
|
||||
|
||||
%h3 Notifying hosts and guests of their placements
|
||||
|
||||
%p At the moment there is no automated tool to do this for you. You will need to download the excel speadsheet at the bottom of the page to get all placements and their contact info.
|
@ -61,6 +61,13 @@
|
||||
.dlg-inner
|
||||
%p.message=''
|
||||
%button.close=_'modals.done_button'
|
||||
- if @help_dlg.present?
|
||||
.dlg#help-dlg{data: { nofocus: 1 }}
|
||||
.dlg-content
|
||||
%h2.title=_'modals.help'
|
||||
.dlg-inner
|
||||
.message=''
|
||||
%button.close=_'modals.done_button'
|
||||
- if @login_dlg.present?
|
||||
.dlg#login-dlg
|
||||
.dlg-content
|
||||
|
@ -1,15 +0,0 @@
|
||||
development:
|
||||
enabled: false
|
||||
host: bikebike.org
|
||||
|
||||
preview:
|
||||
enabled: false
|
||||
host: preview-cdn.bikebike.org
|
||||
protocol: https
|
||||
fallback_protocol: http
|
||||
|
||||
production:
|
||||
enabled: true
|
||||
host: cdn.bikebike.org
|
||||
protocol: https
|
||||
fallback_protocol: http
|
@ -44,7 +44,7 @@ BikeBike::Application.configure do
|
||||
# enable_starttls_auto: true,
|
||||
# openssl_verify_mode: 'none',
|
||||
# user_name: 'info@bikebike.org',
|
||||
# password: config.app_config['email_password']
|
||||
# password: 'Toronto@)!)'
|
||||
# }
|
||||
config.action_mailer.raise_delivery_errors = true
|
||||
config.action_mailer.perform_deliveries = true
|
||||
|
@ -1331,6 +1331,10 @@ en:
|
||||
conference:
|
||||
actions:
|
||||
Register: Register
|
||||
help:
|
||||
link_text: Help
|
||||
headings:
|
||||
admin_housing: Help for Housing
|
||||
modals:
|
||||
confirm: Please Confirm
|
||||
yes_button: 'Yes'
|
||||
@ -1461,10 +1465,9 @@ en:
|
||||
instead of a guest form. If you want to consider surrounding cities as
|
||||
well, enter the distance from %{city} that you wish to be included as
|
||||
providers. Cities are measured from center to center.
|
||||
housing: Pair each housing provider with a list of guests. Try to match
|
||||
guests with hosts and other guests who are good matches and respect their
|
||||
requests, but also keep in mind that we cannot always respect all requests
|
||||
and part of the Bike!Bike! experience is getting to know new people.
|
||||
housing: Match guests with hosts, and fulfill their housing
|
||||
requests to the best of your ability. Use guest notes and the face icons to determine if a guest is a good match for the host.
|
||||
Hover over unhappy faces for details on how to find the guest a better match. Keep in mind that you may not be able to accommodate every request.
|
||||
locations:
|
||||
heading: Locations
|
||||
description: Locations are used to schedule workshops, events, and meals.
|
||||
@ -2079,6 +2082,7 @@ en:
|
||||
quiet: Quiet household
|
||||
pets: House has dogs or cats
|
||||
can_provide_housing: I can provide housing.
|
||||
housing_provider: Host?
|
||||
not_attending: I will not be attending the conference
|
||||
questions:
|
||||
bike:
|
||||
@ -2096,6 +2100,10 @@ en:
|
||||
house: Indoor Location
|
||||
none: I'll take care of it
|
||||
tent: Tent Space
|
||||
housing_short:
|
||||
house: House
|
||||
none: None
|
||||
tent: Tent
|
||||
bikes:
|
||||
medium: Medium
|
||||
none: "(none)"
|
||||
@ -2116,9 +2124,10 @@ en:
|
||||
unregistered: Unregistered
|
||||
preregistered: Preregistered
|
||||
registered: Registered
|
||||
cancelled: Cancelled
|
||||
companion: Companion
|
||||
companion_email: Companion Email
|
||||
Preferred_Languages: Preferred Language
|
||||
Preferred_Languages: Language
|
||||
is_attending: Attending?
|
||||
about_bikebike:
|
||||
paragraphs:
|
||||
@ -2282,6 +2291,8 @@ en:
|
||||
paypal: Online
|
||||
on_arrival: In person
|
||||
none: None
|
||||
payment_method: Payment Method
|
||||
payment_currency: Payment Currency
|
||||
space: Available Space
|
||||
hosting_dates: When will you be in town?
|
||||
type: Type
|
||||
@ -2295,8 +2306,8 @@ en:
|
||||
other: Disabilities, housing preferences, etc.
|
||||
email: Email address
|
||||
allergies: Allergies
|
||||
arrival: Arrival date
|
||||
departure: Departure date
|
||||
arrival: Arrival
|
||||
departure: Departure
|
||||
location: City, State/Province, Country
|
||||
name: Name
|
||||
subject: Subject
|
||||
@ -2306,10 +2317,13 @@ en:
|
||||
notes: Notes
|
||||
message: 'Your Message:'
|
||||
address: Street Address
|
||||
address_short: Address
|
||||
phone: Phone number
|
||||
phone_short: Phone
|
||||
bed_space: Bed/Couch Space
|
||||
floor_space: Floor Space
|
||||
tent_space: Tent Space
|
||||
hosting_space: Space
|
||||
first_day: From
|
||||
last_day: To
|
||||
body: Body
|
||||
@ -2329,7 +2343,7 @@ en:
|
||||
closed: Closed
|
||||
open: Open
|
||||
pre: Pre-Registration
|
||||
registration_status: Registration Status
|
||||
registration_status: Status
|
||||
companion: Email address
|
||||
block_number: Block
|
||||
days: Days
|
||||
@ -2395,6 +2409,10 @@ en:
|
||||
create: Create
|
||||
delete: Delete
|
||||
place_guest: Place Guest
|
||||
place_guest_in:
|
||||
bed_space: Place a guest in a bed or couch
|
||||
floor_space: Place a guest on the floor
|
||||
tent_space: Place a guest in a tent space
|
||||
set_host: Set Host
|
||||
add_comment: Add Comment
|
||||
reply: Reply
|
||||
|
Loading…
x
Reference in New Issue
Block a user