Editable registrations
This commit is contained in:
		
							parent
							
								
									32474fae1c
								
							
						
					
					
						commit
						fe9dd2b493
					
				| @ -3,15 +3,17 @@ | ||||
| 
 | ||||
| 	function filterTable() { | ||||
| 		forEach(document.getElementById('search-table').getElementsByTagName('TBODY')[0].getElementsByTagName('TR'), function(tr) { | ||||
| 			tr.classList.remove('hidden'); | ||||
| 			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'); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| @ -30,39 +32,50 @@ | ||||
| 	function saveRow(row) { | ||||
| 		if (row) { | ||||
| 			row.classList.remove('editing'); | ||||
| 			/*row.removeAttribute('data-editing'); | ||||
| 			forEach(row.getElementsByTagName('TD'), function(cell) { | ||||
| 				var input = cell.getElementsByClassName('cell-editor')[0]; | ||||
| 				if (input) { | ||||
| 					cell.removeChild(input); | ||||
| 			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')); | ||||
| 			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 (selectorMatches(cell, 'tr[data-key].editable td')) { | ||||
| 			editTableRow(cell.parentElement, cell); | ||||
| 		} | ||||
| 		/*var currentRow = document.querySelector('[data-key][data-editing="1"]'); | ||||
| 		if (currentRow && !currentRow.contains(cell)) { | ||||
| 			saveRow(currentRow); | ||||
| 		} | ||||
| 
 | ||||
| 		if (selectorMatches(cell, 'tr[data-key] td[name]')) { | ||||
| 			if (!cell.getElementsByClassName('cell-editor').length) { | ||||
| 				//var tr = cell.parentElement;
 | ||||
| 
 | ||||
| 				//saveRow(document.querySelector('[data-key][data-editing="1"]'), tr);
 | ||||
| 				cell.parentElement.setAttribute('data-editing', "1"); | ||||
| 
 | ||||
| 				var value = cell.innerHTML; | ||||
| 				cell.innerHTML += '<textarea type="text" name="' + cell.getAttribute('name') + '" class="cell-editor">' + value + '</textarea>'; | ||||
| 				cell.parentElement.classList.add(); | ||||
| 				setTimeout(function() { cell.getElementsByClassName('cell-editor')[0].focus(); }, 100); | ||||
| 		} else if (!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')) { | ||||
| @ -78,11 +91,39 @@ | ||||
| 				if (cell) { | ||||
| 					focusElement = editor.querySelector('td[data-column-id="' + cell.getAttribute('data-column-id') + '"] .cell-editor'); | ||||
| 				} | ||||
| 				(focusElement || editor.getElementsByClassName('cell-editor')[0]).focus(); | ||||
| 				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 { | ||||
|  | ||||
| @ -185,7 +185,7 @@ table, .table { | ||||
| 	} | ||||
| 
 | ||||
| 	tr[data-key] { | ||||
| 		cursor: default; | ||||
| 		cursor: cell; | ||||
| 		 | ||||
| 		&:hover { | ||||
| 			background-color: lighten($colour-2, 33%); | ||||
| @ -205,6 +205,16 @@ table, .table { | ||||
| 
 | ||||
| 					&.has-editor { | ||||
| 						opacity: 1; | ||||
| 
 | ||||
| 						@include after { | ||||
| 							content: ''; | ||||
| 							position: absolute; | ||||
| 							top: 100%; | ||||
| 							right: 0; | ||||
| 							left: 0; | ||||
| 							height: 0.25em; | ||||
| 							background-color: rgba($black, 0.125); | ||||
| 						} | ||||
| 					} | ||||
| 
 | ||||
| 					.cell-editor { | ||||
| @ -224,8 +234,13 @@ table, .table { | ||||
| 						overflow: hidden; | ||||
| 						box-shadow: none; | ||||
| 						text-align: inherit; | ||||
| 						//border-bottom: 0.25em solid rgba(0,0,0,0.25); | ||||
| 
 | ||||
| 						&[type=number]::-webkit-inner-spin-button,  | ||||
| 						&[type=number]::-webkit-outer-spin-button {  | ||||
| 							-webkit-appearance: none;  | ||||
| 						} | ||||
| 					} | ||||
| 
 | ||||
| 					select.cell-editor { | ||||
| 						-webkit-appearance: none; | ||||
| 						-moz-appearance: none; | ||||
| @ -233,6 +248,10 @@ table, .table { | ||||
| 						appearance: none; | ||||
| 						cursor: pointer; | ||||
| 					} | ||||
| 
 | ||||
| 					&.date .cell-editor { | ||||
| 						text-align-last: right; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| @ -269,15 +288,32 @@ table, .table { | ||||
| 		td { | ||||
| 			white-space: nowrap; | ||||
| 
 | ||||
| 			&.text { | ||||
| 				white-space: normal; | ||||
| 			} | ||||
| 
 | ||||
| 			&.date, &.datetime, &.money { | ||||
| 			&.date, &.datetime, &.money, &.number { | ||||
| 				font-family: monospace; | ||||
| 				font-size: 1.25em; | ||||
| 				text-align: right; | ||||
| 			} | ||||
| 
 | ||||
| 			&.text { | ||||
| 				max-width: 20em; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	tr.editable td.text, | ||||
| 	tr.editor td.text .value { | ||||
| 		overflow: hidden; | ||||
| 		text-overflow: ellipsis; | ||||
| 	} | ||||
| 			 | ||||
| 	tr.editor { | ||||
| 		td.text .cell-editor { | ||||
| 			white-space: normal; | ||||
| 			bottom: auto; | ||||
| 			height: 10em; | ||||
| 			z-index: 1; | ||||
| 			background: inherit; | ||||
| 			overflow: auto !important; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -336,94 +336,7 @@ class ConferencesController < ApplicationController | ||||
| 					end | ||||
| 				end | ||||
| 			when :stats | ||||
| 				@registrations = ConferenceRegistration.where(:conference_id => @this_conference.id).sort { |a,b| (a.user.present? ? (a.user.firstname || '') : '').downcase <=> (b.user.present? ? (b.user.firstname || '') : '').downcase } | ||||
| 				@excel_data = { | ||||
| 					columns: [ | ||||
| 							:name, | ||||
| 							:email, | ||||
| 							:status, | ||||
| 							:registration_fees_paid, | ||||
| 							:date, | ||||
| 							:city, | ||||
| 							:preferred_language, | ||||
| 							:languages, | ||||
| 							:arrival, | ||||
| 							:departure, | ||||
| 							:housing, | ||||
| 							:bike, | ||||
| 							:food, | ||||
| 							:companion, | ||||
| 							:companion_email, | ||||
| 							:allergies | ||||
| 						], | ||||
| 					column_types: { | ||||
| 							name: :bold, | ||||
| 							date: :datetime, | ||||
| 							arrival: [:date, :day], | ||||
| 							departure: [:date, :day], | ||||
| 							registration_fees_paid: :money, | ||||
| 							allergies: :text | ||||
| 						}, | ||||
| 					keys: { | ||||
| 							name: 'forms.labels.generic.name', | ||||
| 							email: 'forms.labels.generic.email', | ||||
| 							status: 'forms.labels.generic.registration_status', | ||||
| 							city: 'forms.labels.generic.location', | ||||
| 							date: 'articles.conference_registration.terms.Date', | ||||
| 							languages: 'articles.conference_registration.terms.Languages', | ||||
| 							preferred_language: 'articles.conference_registration.terms.Preferred_Languages', | ||||
| 							arrival: 'forms.labels.generic.arrival', | ||||
| 							departure: 'forms.labels.generic.departure', | ||||
| 							housing: 'forms.labels.generic.housing', | ||||
| 							bike: 'forms.labels.generic.bike', | ||||
| 							food: 'forms.labels.generic.food', | ||||
| 							companion: 'articles.conference_registration.terms.companion', | ||||
| 							companion_email: 'forms.labels.generic.email', | ||||
| 							allergies: 'forms.labels.generic.allergies', | ||||
| 							registration_fees_paid: 'articles.conference_registration.headings.fees_paid' | ||||
| 						}, | ||||
| 					data: [] | ||||
| 				} | ||||
| 				@registrations.each do | r | | ||||
| 					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? | ||||
| 						steps = r.steps_completed || [] | ||||
| 
 | ||||
| 						@excel_data[:data] << { | ||||
| 							id: r.id, | ||||
| 							name: user.firstname || '', | ||||
| 							email: user.email || '', | ||||
| 							status: (view_context._"articles.conference_registration.terms.registration_status.#{(steps.include? 'questions') ? 'registered' : ((steps.include? 'contact_info') ? 'preregistered' : 'unregistered')}"), | ||||
| 							date: r.created_at ? r.created_at.strftime("%F %T") : '', | ||||
| 							city: r.city || '', | ||||
| 							preferred_language: user.locale.present? ? (view_context.language_name user.locale) : '', | ||||
| 							languages: ((r.languages || []).map { |x| view_context.language_name x }).join(', ').to_s, | ||||
| 							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}") : '', | ||||
| 							companion: companion, | ||||
| 							companion_email: ((r.housing_data || {})['companions'] || ['']).first, | ||||
| 							allergies: r.allergies, | ||||
| 							registration_fees_paid: r.registration_fees_paid, | ||||
| 							raw_values: { | ||||
| 								housing: r.housing, | ||||
| 								bike: r.bike, | ||||
| 								food: r.food, | ||||
| 								arrival: r.arrival, | ||||
| 								departure: r.departure | ||||
| 							}, | ||||
| 							html_values: { | ||||
| 								date: r.created_at.present? ? r.created_at.strftime("%F %T") : '', | ||||
| 								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) : '' | ||||
| 							} | ||||
| 						} | ||||
| 					end | ||||
| 				end | ||||
| 				get_stats(!request.format.xlsx?) | ||||
| 
 | ||||
| 				if request.format.xlsx? | ||||
| 					logger.info "Generating stats.xls" | ||||
| @ -437,22 +350,6 @@ class ConferencesController < ApplicationController | ||||
| 					@donation_count = 0 | ||||
| 					@donations = 0 | ||||
| 					@food = { meat: 0, vegan: 0, vegetarian: 0, all: 0 } | ||||
| 					@column_options = { | ||||
| 						housing: ConferenceRegistration.all_housing_options.map { |h| [ | ||||
| 							(view_context._"articles.conference_registration.questions.housing.#{h}"), | ||||
| 							h] }, | ||||
| 						bike: ConferenceRegistration.all_bike_options.map { |b| [ | ||||
| 							(view_context._"articles.conference_registration.questions.bike.#{b}"), | ||||
| 							b] }, | ||||
| 						food: ConferenceRegistration.all_food_options.map { |f| [ | ||||
| 							(view_context._"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), | ||||
| 						preferred_language: I18n.backend.enabled_locales.map { |l| [ | ||||
| 								(view_context.language_name l), l | ||||
| 							] } | ||||
| 					} | ||||
| 					@registrations.each do | r | | ||||
| 						if r.steps_completed.include? 'questions' | ||||
| 							@completed_registrations += 1 | ||||
| @ -576,6 +473,191 @@ class ConferencesController < ApplicationController | ||||
| 
 | ||||
| 	end | ||||
| 
 | ||||
| 	def get_stats(html_format = false, id = nil) | ||||
| 		@registrations = ConferenceRegistration.where(:conference_id => @this_conference.id).sort { |a,b| (a.user.present? ? (a.user.firstname || '') : '').downcase <=> (b.user.present? ? (b.user.firstname || '') : '').downcase } | ||||
| 		@excel_data = { | ||||
| 			columns: [ | ||||
| 					:name, | ||||
| 					:email, | ||||
| 					:status, | ||||
| 					:is_attending, | ||||
| 					:registration_fees_paid, | ||||
| 					:date, | ||||
| 					:city, | ||||
| 					:preferred_language | ||||
| 				] + | ||||
| 				User.AVAILABLE_LANGUAGES.map { |l| "language_#{l}".to_sym } + | ||||
| 				[	 | ||||
| 					:arrival, | ||||
| 					:departure, | ||||
| 					:housing, | ||||
| 					:bike, | ||||
| 					:food, | ||||
| 					:companion, | ||||
| 					:companion_email, | ||||
| 					:allergies, | ||||
| 					:other, | ||||
| 					:can_provide_housing, | ||||
| 					:first_day, | ||||
| 					:last_day, | ||||
| 					:address, | ||||
| 					:phone | ||||
| 				] + ConferenceRegistration.all_spaces + [ | ||||
| 					:notes | ||||
| 				], | ||||
| 			column_types: { | ||||
| 					name: :bold, | ||||
| 					date: :datetime, | ||||
| 					companion_email: :email, | ||||
| 					arrival: [:date, :day], | ||||
| 					departure: [:date, :day], | ||||
| 					registration_fees_paid: :money, | ||||
| 					allergies: :text, | ||||
| 					other: :text, | ||||
| 					first_day: [:date, :day], | ||||
| 					last_day: [:date, :day], | ||||
| 					notes: :text | ||||
| 				}, | ||||
| 			keys: { | ||||
| 					name: 'forms.labels.generic.name', | ||||
| 					email: 'forms.labels.generic.email', | ||||
| 					status: 'forms.labels.generic.registration_status', | ||||
| 					is_attending: 'articles.conference_registration.terms.is_attending', | ||||
| 					city: 'forms.labels.generic.location', | ||||
| 					date: 'articles.conference_registration.terms.Date', | ||||
| 					preferred_language: 'articles.conference_registration.terms.Preferred_Languages', | ||||
| 					arrival: 'forms.labels.generic.arrival', | ||||
| 					departure: 'forms.labels.generic.departure', | ||||
| 					housing: 'forms.labels.generic.housing', | ||||
| 					bike: 'forms.labels.generic.bike', | ||||
| 					food: 'forms.labels.generic.food', | ||||
| 					companion: 'articles.conference_registration.terms.companion', | ||||
| 					companion_email: 'forms.labels.generic.email', | ||||
| 					allergies: 'forms.labels.generic.allergies', | ||||
| 					registration_fees_paid: 'articles.conference_registration.headings.fees_paid', | ||||
| 					other: 'articles.conference_registration.headings.other', | ||||
| 					can_provide_housing: 'articles.conference_registration.can_provide_housing', | ||||
| 					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' | ||||
| 				}, | ||||
| 			data: [] | ||||
| 		} | ||||
| 		User.AVAILABLE_LANGUAGES.each do | l | | ||||
| 			@excel_data[:keys]["language_#{l}".to_sym] = "languages.#{l.to_s}"  | ||||
| 		end | ||||
| 		ConferenceRegistration.all_spaces.each do |s| | ||||
| 			@excel_data[:column_types][s] = :number | ||||
| 			@excel_data[:keys][s] = "forms.labels.generic.#{s.to_s}" | ||||
| 		end | ||||
| 		@registrations.each do | r | | ||||
| 			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? | ||||
| 				steps = r.steps_completed || [] | ||||
| 
 | ||||
| 				if id.nil? || id == r.id | ||||
| 					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? | ||||
| 
 | ||||
| 					data = { | ||||
| 						id: r.id, | ||||
| 						name: user.firstname || '', | ||||
| 						email: user.email || '', | ||||
| 						status: (view_context._"articles.conference_registration.terms.registration_status.#{(steps.include? 'questions') ? 'registered' : ((steps.include? 'contact_info') ? 'preregistered' : 'unregistered')}"), | ||||
| 						is_attending: (view_context._"articles.conference_registration.questions.bike.#{r.is_attending == 'n' ? 'no' : 'yes'}"), | ||||
| 						date: r.created_at ? r.created_at.strftime("%F %T") : '', | ||||
| 						city: r.city || '', | ||||
| 						preferred_language: user.locale.present? ? (view_context.language_name user.locale) : '', | ||||
| 						#languages: ((r.languages || []).map { |x| view_context.language_name x }).join(', ').to_s, | ||||
| 						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}") : '', | ||||
| 						companion: companion, | ||||
| 						companion_email: (housing_data['companions'] || ['']).first, | ||||
| 						allergies: r.allergies, | ||||
| 						registration_fees_paid: r.registration_fees_paid, | ||||
| 						other: r.other, | ||||
| 						can_provide_housing: r.can_provide_housing ? (view_context._'articles.conference_registration.questions.bike.yes') : '', | ||||
| 						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: { | ||||
| 							housing: r.housing, | ||||
| 							bike: r.bike, | ||||
| 							food: r.food, | ||||
| 							arrival: r.arrival.present? ? r.arrival.to_date : nil, | ||||
| 							departure: r.departure.present? ? r.departure.to_date : nil, | ||||
| 							preferred_language: user.locale, | ||||
| 							is_attending: r.is_attending != 'n', | ||||
| 							can_provide_housing: r.can_provide_housing, | ||||
| 							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") : '', | ||||
| 							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) : '', | ||||
| 							last_day: availability[1].present? ? view_context.date(availability[1].to_date, :span_same_year_date_1) : '' | ||||
| 						} | ||||
| 					} | ||||
| 					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[: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 | ||||
| 					@excel_data[:data] << data | ||||
| 				end | ||||
| 			end | ||||
| 		end | ||||
| 
 | ||||
| 		if html_format | ||||
| 			yes_no = [ | ||||
| 						[(view_context._"articles.conference_registration.questions.bike.yes"), true], | ||||
| 						[(view_context._"articles.conference_registration.questions.bike.no"), false] | ||||
| 					] | ||||
| 			@column_options = { | ||||
| 				housing: ConferenceRegistration.all_housing_options.map { |h| [ | ||||
| 					(view_context._"articles.conference_registration.questions.housing.#{h}"), | ||||
| 					h] }, | ||||
| 				bike: ConferenceRegistration.all_bike_options.map { |b| [ | ||||
| 					(view_context._"articles.conference_registration.questions.bike.#{b}"), | ||||
| 					b] }, | ||||
| 				food: ConferenceRegistration.all_food_options.map { |f| [ | ||||
| 					(view_context._"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), | ||||
| 				preferred_language: I18n.backend.enabled_locales.map { |l| [ | ||||
| 						(view_context.language_name l), l | ||||
| 					] }, | ||||
| 				is_attending: yes_no, | ||||
| 				can_provide_housing: yes_no, | ||||
| 				first_day: view_context.conference_days_options_list(:before), | ||||
| 				last_day: view_context.conference_days_options_list(:after) | ||||
| 			} | ||||
| 			User.AVAILABLE_LANGUAGES.each do | l | | ||||
| 				@column_options["language_#{l}".to_sym] = [ | ||||
| 						[(view_context._"articles.conference_registration.questions.bike.yes"), true] | ||||
| 					] | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 
 | ||||
| 	def get_housing_data | ||||
| 		@hosts = {} | ||||
| 		@guests = {} | ||||
| @ -699,6 +781,60 @@ class ConferencesController < ApplicationController | ||||
| 		@admin_step = params[:admin_step] | ||||
| 
 | ||||
| 		case params[:admin_step] | ||||
| 		when 'stats' | ||||
| 			registration = ConferenceRegistration.where( | ||||
| 						id: params[:key].to_i, | ||||
| 						conference_id: @this_conference.id | ||||
| 					).limit(1).first | ||||
| 			user_changed = false | ||||
| 			params.each do | key, value | | ||||
| 				case key.to_sym | ||||
| 				when :city | ||||
| 					registration.city = value.present? ? view_context.location(Geocoder.search(value, language: @this_conference.locale).first, @this_conference.locale) : nil | ||||
| 				when :housing, :bike, :food, :allergies, :other | ||||
| 					registration.send("#{key.to_s}=", value) | ||||
| 				when :registration_fees_paid | ||||
| 					registration.registration_fees_paid = value.to_i | ||||
| 				when :can_provide_housing | ||||
| 					registration.send("#{key.to_s}=", value.present?) | ||||
| 				when :arrival, :departure | ||||
| 					registration.send("#{key.to_s}=", value.present? ? Date.parse(value) : nil) | ||||
| 				when :companion_email | ||||
| 					registration.housing_data ||= {} | ||||
| 					registration.housing_data['companions'] = [value] | ||||
| 				when :preferred_language | ||||
| 					registration.user.locale = value | ||||
| 					user_changed = true | ||||
| 				when :is_attending | ||||
| 					registration.is_attending = value.present? ? 'y' : 'n' | ||||
| 				when :address, :phone, :first_day, :last_day, :notes | ||||
| 					registration.housing_data ||= {} | ||||
| 					registration.housing_data[key.to_s] = value | ||||
| 				else | ||||
| 					if key.start_with?('language_') | ||||
| 						l = key.split('_').last | ||||
| 						if User.AVAILABLE_LANGUAGES.include? l.to_sym | ||||
| 							registration.user.languages ||= [] | ||||
| 							if value.present? | ||||
| 								registration.user.languages |= [l] | ||||
| 							else | ||||
| 								registration.user.languages -= [l] | ||||
| 							end | ||||
| 							user_changed = true | ||||
| 						end | ||||
| 					elsif ConferenceRegistration.all_spaces.include? key.to_sym | ||||
| 						registration.housing_data ||= {} | ||||
| 						registration.housing_data['space'] ||= {} | ||||
| 						registration.housing_data['space'][key.to_s] = value | ||||
| 					end | ||||
| 				end | ||||
| 			end | ||||
| 			registration.user.save! if user_changed | ||||
| 			registration.save! | ||||
| 			get_stats(true, params[:key].to_i)  | ||||
| 			options = view_context.registrations_table_options | ||||
| 			options[:html] = true | ||||
| 			return render html: view_context.excel_rows(@excel_data, {}, options) | ||||
| 		when 'edit' | ||||
| 			case params[:button] | ||||
| 			when 'save' | ||||
|  | ||||
| @ -756,7 +756,7 @@ module ApplicationHelper | ||||
| 			belongs_to_periods << :before_plus_one if day <= (conference.start_date + 1.day) | ||||
| 			belongs_to_periods << :after_minus_one if day >= (conference.end_date - 1.day) | ||||
| 			belongs_to_periods << :during if day >= conference.start_date && day <= conference.end_date | ||||
| 			days << [date(day.to_date, format || :span_same_year_date_1), day] if belongs_to_periods.include?(period) | ||||
| 			days << [date(day.to_date, format || :span_same_year_date_1), day.to_date] if belongs_to_periods.include?(period) | ||||
| 		end | ||||
| 		return days | ||||
| 	end | ||||
| @ -1558,6 +1558,7 @@ module ApplicationHelper | ||||
| 			format 'td.datetime', num_fmt: 22, font_name: 'Courier New', sz: 10, fg_color: '333333' | ||||
| 			format 'td.date.day', num_fmt: 14, font_name: 'Courier New', sz: 10, fg_color: '333333' | ||||
| 			format 'td.money', num_fmt: 2, font_name: 'Courier New', sz: 10, fg_color: '333333' | ||||
| 			format 'td.number', font_name: 'Courier New', sz: 10, fg_color: '333333' | ||||
| 			format 'td.bold', font_name: 'Calibri', fg_color: '333333', b: true | ||||
| 		end | ||||
| 
 | ||||
| @ -1670,16 +1671,27 @@ module ApplicationHelper | ||||
| 
 | ||||
| 				if (options[:column_names] || []).include? column | ||||
| 					attributes[:class] << 'has-editor' | ||||
| 					raw_value = value | ||||
| 					raw_value = row[:raw_values][column] || value | ||||
| 
 | ||||
| 					if options[:html] && row[:html_values].present? && row[:html_values][column].present? | ||||
| 						value = row[:html_values][column] | ||||
| 					end | ||||
| 
 | ||||
| 					editor_attributes = { class: 'cell-editor', data: { value: raw_value.to_s } } | ||||
| 
 | ||||
| 					# create the control but add the original value to set the width and height | ||||
| 					editor_value = content_tag(:span, CGI::escapeHTML(value), class: 'value') | ||||
| 					if (options[:column_options] || {})[column].present? | ||||
| 						value = (value + select_tag(column, options_for_select(options[:column_options][column], row[:raw_values][column] || raw_value), class: 'cell-editor')).html_safe | ||||
| 						value = (editor_value.html_safe + select_tag(column, options_for_select([['', '']] + options[:column_options][column], raw_value), editor_attributes)).html_safe | ||||
| 					elsif data[:column_types][column] == :text | ||||
| 						editor_attributes[:name] = column | ||||
| 						value = (editor_value.html_safe + content_tag(:textarea, raw_value, editor_attributes)).html_safe | ||||
| 					else | ||||
| 						value = (value + content_tag(:textarea, raw_value, name: column, class: 'cell-editor')).html_safe | ||||
| 						editor_attributes[:name] = column | ||||
| 						editor_attributes[:value] = raw_value | ||||
| 						type = data[:column_types][column] || :unknown | ||||
| 						editor_attributes[:type] = { money: :number, number: :number, email: :email }[type] || :text | ||||
| 						value = (editor_value.html_safe + content_tag(:input, nil, editor_attributes)).html_safe | ||||
| 					end | ||||
| 				end | ||||
| 
 | ||||
| @ -1724,7 +1736,6 @@ module ApplicationHelper | ||||
| 			 | ||||
| 			if options[:editable] | ||||
| 				attributes[:class] << :editable | ||||
| 				# attributes[:tabindex] = 0 | ||||
| 			end | ||||
| 			 | ||||
| 			rows += content_tag(:tr, excel_columns(row, data, padding, options), attributes) + | ||||
| @ -1734,6 +1745,38 @@ module ApplicationHelper | ||||
| 		rows.html_safe | ||||
| 	end | ||||
| 
 | ||||
| 	def registrations_table_options | ||||
| 		{ | ||||
| 			id: 'search-table', | ||||
| 			class: ['registrations', 'admin-edit'], | ||||
| 			primary_key: :id, | ||||
| 			column_names: [ | ||||
| 					:registration_fees_paid, | ||||
| 					:is_attending, | ||||
| 					:city, | ||||
| 					:preferred_language, | ||||
| 					:arrival, | ||||
| 					:departure, | ||||
| 					:housing, | ||||
| 					:bike, | ||||
| 					:food, | ||||
| 					:companion_email, | ||||
| 					:allergies, | ||||
| 					:other, | ||||
| 					:can_provide_housing, | ||||
| 					:address, | ||||
| 					:phone, | ||||
| 					:first_day, | ||||
| 					:last_day, | ||||
| 					:notes | ||||
| 				] + | ||||
| 				User.AVAILABLE_LANGUAGES.map { |l| "language_#{l}".to_sym } + | ||||
| 				ConferenceRegistration.all_spaces, | ||||
| 			editable: administration_update_path(@this_conference.slug, :stats), | ||||
| 			column_options: @column_options | ||||
| 		} | ||||
| 	end | ||||
| 
 | ||||
| 	private | ||||
| 		def _original_content(value, lang) | ||||
| 			content_tag(:div, ( | ||||
|  | ||||
| @ -13,6 +13,10 @@ class ConferenceRegistration < ActiveRecord::Base | ||||
| 		[:none, :tent, :house] | ||||
| 	end | ||||
| 
 | ||||
| 	def self.all_spaces | ||||
| 		[:bed_space, :floor_space, :tent_space] | ||||
| 	end | ||||
| 
 | ||||
| 	def self.all_bike_options | ||||
| 		[:yes, :no] | ||||
| 	end | ||||
| @ -20,4 +24,8 @@ class ConferenceRegistration < ActiveRecord::Base | ||||
| 	def self.all_food_options | ||||
| 		[:meat, :vegetarian, :vegan] | ||||
| 	end | ||||
| 
 | ||||
| 	def self.all_considerations | ||||
| 		[:vegan, :smoking, :pets, :quiet] | ||||
| 	end | ||||
| end | ||||
|  | ||||
| @ -13,7 +13,7 @@ class User < ActiveRecord::Base | ||||
|     accepts_nested_attributes_for :authentications | ||||
| 
 | ||||
| 	before_save do |user| | ||||
| 		user.locale = I18n.locale | ||||
| 		user.locale ||= I18n.locale | ||||
| 	end | ||||
| 
 | ||||
| 	def can_translate?(to_locale = nil, from_locale = nil) | ||||
| @ -48,9 +48,6 @@ class User < ActiveRecord::Base | ||||
| 		user = where(email: email).first | ||||
| 
 | ||||
| 		unless user | ||||
| 			# not really a good UX so we should fix this later | ||||
| 			#do_404 | ||||
| 			#return | ||||
| 			user = new(email: email) | ||||
| 			user.save! | ||||
| 		end | ||||
|  | ||||
| @ -6,14 +6,14 @@ | ||||
| 			= textfield :address, @hosting_data['address'], required: true, heading: 'articles.conference_registration.headings.host.address', help: 'articles.conference_registration.paragraphs.host.address' | ||||
| 			= telephonefield :phone, @hosting_data['phone'], required: true | ||||
| 			= fieldset :space, heading: 'articles.conference_registration.headings.host.space', help: 'articles.conference_registration.paragraphs.host.space' do | ||||
| 				- [:bed_space, :floor_space, :tent_space].each do | space | | ||||
| 				- ConferenceRegistration.all_spaces.each do | space | | ||||
| 					= numberfield space, @hosting_data['space'][space.to_s] || 0, min: 0, required: true | ||||
| 			= fieldset :hosting_dates, heading: 'articles.conference_registration.headings.host.availability', help: 'articles.conference_registration.paragraphs.host.availability' do | ||||
| 				- first_day_options = conference_days_options_list(:before) | ||||
| 				- last_day_options = conference_days_options_list(:after) | ||||
| 				= selectfield :first_day, @hosting_data['availability'][0] || first_day_options.first.last, first_day_options | ||||
| 				= selectfield :last_day, @hosting_data['availability'][1] || last_day_options.last.last, last_day_options | ||||
| 			= checkboxes :considerations, [:vegan, :smoking, :pets, :quiet], @hosting_data['considerations'], 'articles.conference_registration.host.considerations', heading: 'articles.conference_registration.headings.host.considerations', help: 'articles.conference_registration.paragraphs.host.considerations', vertical: true | ||||
| 			= checkboxes :considerations, ConferenceRegistration.all_considerations, @hosting_data['considerations'], 'articles.conference_registration.host.considerations', heading: 'articles.conference_registration.headings.host.considerations', help: 'articles.conference_registration.paragraphs.host.considerations', vertical: true | ||||
| 			= textarea :notes, @hosting_data['notes'], help: 'articles.conference_registration.paragraphs.host.notes', edit_on: :focus | ||||
| 		.actions.next-prev | ||||
| 			= button_tag (params[:step] == :save ? :save : :next), value: :hosting | ||||
|  | ||||
| @ -22,4 +22,4 @@ | ||||
| %h4 Registrations | ||||
| = searchfield :search, nil, big: true | ||||
| .table-scroller | ||||
| 	= html_table @excel_data, id: 'search-table', class: ['registrations', 'admin-edit'], primary_key: :id, column_names: [:registration_fees_paid, :city, :preferred_language, :arrival, :departure, :housing, :bike, :food, :companion_email, :allergies], editable: administration_update_path(@this_conference.slug, :stats), column_options: @column_options | ||||
| 	= html_table @excel_data, registrations_table_options | ||||
|  | ||||
| @ -1117,6 +1117,7 @@ en: | ||||
|           registered: Registered | ||||
|         companion: Companion | ||||
|         Preferred_Languages: Preferred Language | ||||
|         is_attending: Attending? | ||||
|     about_bikebike: | ||||
|       paragraphs: | ||||
|         bicycle_project_paragraph: 'From collectives that use the bicycle as an excuse to change society, economy and the environment. Non-profit groups that have a community bike shops, cooperatives and other projects that promote the use of the bicycle and that come together to turn their communities into a place where riding is easier, more inclusive, safer and more fun. The list below uses the criteria found in the old Bicycle Organization Organization Project for what constitutes a community bike shop. The bike project need not meet all these criteria. Rather, it is a general list of qualities which are common among many bicycle projects.' | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user