Skip to content

Commit 33eea36

Browse files
thisismeonmounteverestthisismeonmounteverest
andauthored
Progress for profile pages. (#389)
* Finishing profile pages. * Warmup cache so that translation are available for Javascript. * Warmup cache for test environment to be able to access database. * Fixing code smells. * Working on migration of database content and profile pages. * Fixing code smells. --------- Co-authored-by: thisismeonmounteverest <shevek@blafaselblubb.abcde.biz>
1 parent 409877b commit 33eea36

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+6352
-5300
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ jobs:
9292
- name: Create test database
9393
run: bin/console test:database:create --env=test
9494

95+
- name: Warmup cache
96+
run: bin/console cache:clear --env=test
97+
9598
- name: Setup Yarn
9699
uses: threeal/setup-yarn-action@v2.0.0
97100
with:

assets/js/accommodation_widget.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import {default as rangeSlider} from 'rangeslider-pure';
2+
import {trans} from './translator'
3+
4+
export { initializeAccommodationWidget }
5+
6+
const accommodationRadiobuttons = document.querySelectorAll(".js-accommodation");
7+
const hostingInterest = document.getElementById('hosting_interest');
8+
const radioHandler = (event) => {
9+
if (event.target.type === 'radio') {
10+
if (event.target.value === 'no') {
11+
hostingInterest.classList.remove('u:block');
12+
hostingInterest.classList.add('u:hidden');
13+
} else {
14+
hostingInterest.classList.remove('u:hidden');
15+
hostingInterest.classList.add('u:block');
16+
}
17+
accommodationRadiobuttons.forEach( (radio) => {
18+
radio.parentElement.classList.remove('u:bg-gray-400')
19+
})
20+
event.target.parentElement.classList.add('u:bg-gray-400');
21+
}
22+
}
23+
24+
const markers = [
25+
trans('hosting_interest.select'),
26+
trans('hosting_interest.very_low'),
27+
trans('hosting_interest.low'),
28+
trans('hosting_interest.lower'),
29+
trans('hosting_interest.low_to_medium'),
30+
trans('hosting_interest.medium'),
31+
trans('hosting_interest.medium_to_high'),
32+
trans('hosting_interest.high'),
33+
trans('hosting_interest.higher'),
34+
trans('hosting_interest.very_high'),
35+
trans('hosting_interest.cant_wait')
36+
]
37+
38+
const slider = document.querySelectorAll('input[type="range"]');
39+
40+
function updateValueOutput(value) {
41+
const valueOutput = document.getElementsByClassName('rangeSlider__value-output');
42+
if (valueOutput.length) {
43+
valueOutput[0].innerHTML = markers[value];
44+
}
45+
}
46+
47+
const initializeHostingInterestSlider = () => {
48+
return rangeSlider.create(slider, {
49+
onInit: function () {
50+
updateValueOutput(0);
51+
},
52+
onSlide: function (value, percent, position) {
53+
updateValueOutput(value);
54+
}
55+
});
56+
};
57+
58+
const initializeAccommodationRadioButtons = () => {
59+
accommodationRadiobuttons.forEach( (radio) => {
60+
radio.addEventListener("click", radioHandler)
61+
})
62+
}
63+
64+
const initializeAccommodationWidget = () => {
65+
initializeAccommodationRadioButtons()
66+
initializeHostingInterestSlider()
67+
}

assets/js/calendar.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Calendar } from 'vanilla-calendar-pro';
2+
import 'vanilla-calendar-pro/styles/index.css';
3+
import * as dayjs from 'dayjs'
4+
5+
export { initializeCalendar }
6+
7+
const htmlTag = document.getElementsByTagName('html')[0];
8+
const lang = htmlTag.attributes['lang'].value;
9+
10+
const minimumAge = dayjs().subtract(18, 'year');
11+
const maximumAge = minimumAge.subtract(122, 'year');
12+
13+
const options = {
14+
inputMode: true,
15+
type: 'default',
16+
onChangeToInput(self) {
17+
if (!self.context.inputElement) return;
18+
if (self.context.selectedDates[0]) {
19+
self.context.inputElement.value = self.context.selectedDates[0];
20+
self.hide();
21+
} else {
22+
self.context.inputElement.value = '';
23+
}
24+
},
25+
lang: lang,
26+
dateMin: maximumAge.format('YYYY-MM-DD'),
27+
dateMax: minimumAge.format('YYYY-MM-DD'),
28+
positionToInput: 'auto',
29+
selectedTheme: 'light',
30+
disabledDates: [],
31+
dateToday: minimumAge.toDate(),
32+
};
33+
34+
const initializeCalendar = (id) => {
35+
const calendarAnchor = document.getElementById(id);
36+
const calendar = new Calendar(calendarAnchor, options);
37+
calendar.init();
38+
}

assets/js/profile/account.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { initializeCalendar} from "../calendar";
2+
3+
initializeCalendar('account_edit_form_birthdate')
Lines changed: 69 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,78 @@
1-
import { default as rangeSlider } from 'rangeslider-pure';
1+
import { initializeAccommodationWidget } from "../accommodation_widget";
22

3-
const slider = document.querySelectorAll('input[type="range"]');
3+
const hostingInterest = document.getElementById('accommodation_form_hosting_interest')
44

5-
function updateValueOutput(value) {
6-
const valueOutput = document.getElementsByClassName('rangeSlider__value-output');
7-
if (valueOutput.length) {
8-
valueOutput[0].innerHTML = markers[value];
5+
initializeAccommodationWidget()
6+
7+
// now register on change handler for the radio buttons to change state when the user clicks
8+
9+
const updateAccommodation = async (e) => {
10+
const accommodation = document.querySelector('input[name="accommodation_form[accommodation]"]:checked').value;
11+
const newAccommodationValue = {
12+
accommodation: accommodation,
13+
hostingInterest: +hostingInterest.value
914
}
10-
}
1115

12-
const initializeSlider = () => {
13-
return rangeSlider.create(slider, {
14-
onInit: function() {
15-
updateValueOutput(0);
16+
await fetch('/members/update/accommodation', {
17+
method: 'POST',
18+
headers: {
19+
'Accept': 'application/json',
20+
'Content-Type': 'application/json'
1621
},
17-
onSlide: function(value, percent, position) {
18-
updateValueOutput(value);
19-
}
20-
});
21-
};
22-
23-
initializeSlider();
24-
25-
const accommodationRadiobuttons = document.querySelectorAll(".btn-light");
26-
const hostingInterest = document.getElementById('hosting_interest');
27-
const radioHandler = (event) => {
28-
if (event.target.type === 'radio') {
29-
if (event.target.value === 'no') {
30-
hostingInterest.classList.remove('u:block');
31-
hostingInterest.classList.add('u:hidden');
32-
} else {
33-
hostingInterest.classList.remove('u:hidden');
34-
hostingInterest.classList.add('u:block');
35-
}
22+
body: JSON.stringify(newAccommodationValue)
23+
}).then((response) => {
24+
})
25+
}
26+
27+
const updateOffers = async (e) => {
28+
const newOffers = {
29+
dinner: offers[0].checked,
30+
tour: offers[1].checked,
31+
accessible: offers[2].checked
3632
}
33+
34+
await fetch('/members/update/offers', {
35+
method: 'POST',
36+
headers: {
37+
'Accept': 'application/json',
38+
'Content-Type': 'application/json'
39+
},
40+
body: JSON.stringify(newOffers)
41+
}).then((response) => {
42+
})
3743
}
3844

39-
for (let radio of accommodationRadiobuttons) {
40-
radio.addEventListener("click", radioHandler)
45+
const updateRestrictions = async (e) => {
46+
const newRestrictions = {
47+
noAlcohol: restrictions[0].checked,
48+
noSmoking: restrictions[1].checked,
49+
noDrugs: restrictions[2].checked
50+
}
51+
52+
await fetch('/members/update/restrictions', {
53+
method: 'POST',
54+
headers: {
55+
'Accept': 'application/json',
56+
'Content-Type': 'application/json'
57+
},
58+
body: JSON.stringify(newRestrictions)
59+
}).then((response) => {
60+
})
4161
}
62+
63+
const accommodationRadiobuttons = document.querySelectorAll(('.js-accommodation'))
64+
accommodationRadiobuttons.forEach( (radio) => {
65+
radio.addEventListener("change", updateAccommodation)
66+
})
67+
68+
hostingInterest.addEventListener("change", updateAccommodation)
69+
70+
const offers = document.querySelectorAll('[data-offer]')
71+
offers.forEach( (offer) => {
72+
offer.addEventListener("change", updateOffers)
73+
})
74+
75+
const restrictions = document.querySelectorAll('[data-restrictions]')
76+
restrictions.forEach( (restriction) => {
77+
restriction.addEventListener("change", updateRestrictions)
78+
})

assets/js/roxeditor.js

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,9 @@ const config = {
118118
]
119119
},
120120
autosave: {
121+
waitingTime: 2000,
121122
save( editor ) {
122-
return saveData( editor );
123+
return saveData( editor, false );
123124
}
124125
},
125126
ckfinder: {
@@ -164,6 +165,24 @@ sourceElements.forEach( (element) => {
164165

165166
editor
166167
.then( editor => {
168+
editor.ui.focusTracker.on( 'change:isFocused', ( evt, data, isFocused ) => {
169+
console.log(editor.sourceElement.id + " - " + isFocused)
170+
171+
const host = editor.sourceElement;
172+
const editorType = host.dataset.editorType;
173+
174+
if (editorType === 'inline') {
175+
const progress = document.getElementById(host.dataset.progress)
176+
177+
if (isFocused) {
178+
progress.classList.remove('u:hidden')
179+
progress.classList.add('u:bg-bewelcome')
180+
} else {
181+
saveData(editor, true)
182+
}
183+
}
184+
} );
185+
167186
editors.set(element.id, editor)
168187

169188
const form = editor.sourceElement.closest('form')
@@ -194,27 +213,49 @@ sourceElements.forEach( (element) => {
194213

195214
function registerSubmitHandler( form ) {
196215
form.addEventListener('submit', function( form ) {
197-
// get all editors and set data on hidden input for inline and decoupled editor
198-
// then remove data from localeStorage
199-
for (let [id, editor] of editors.entries()) {
216+
// Remove data from localeStorage.
217+
for (let [editor] of editors.entries()) {
200218
const element = editor.sourceElement
201219

202-
if (element.dataset.editorType === 'inline') {
203-
const input = document.getElementById(element.dataset.input)
204-
input.value = editor.getData()
205-
}
206-
207220
window.localStorage.removeItem(element.id);
208221
}
209222
})
210223
}
211224

212-
function saveData( editor ) {
225+
async function saveData( editor, lostFocus ) {
226+
const element = document.getElementById(editor.sourceElement.id)
227+
213228
const lastChange = new Date();
229+
const language = element.dataset.language;
230+
const storageKey = editor.sourceElement.id + "-" + (language ? language : '');
214231

215-
window.localStorage.setItem(editor.sourceElement.id, JSON.stringify({
232+
window.localStorage.setItem(storageKey, JSON.stringify({
216233
lastChange: lastChange,
217234
editorData: editor.getData()
218235
}));
219-
}
220236

237+
if (lostFocus) {
238+
// Only triggered for inline editor: messages, forum posts, trips description stay keep the data till form submit
239+
const progress = document.getElementById(element.dataset.progress);
240+
241+
if (progress) {
242+
progress.classList.add('u:bg-bewelcome', 'u:animate-pulse')
243+
}
244+
245+
// Post data to the server
246+
const form = new FormData();
247+
form.append('field', element.dataset.field);
248+
form.append('language', element.dataset.language);
249+
form.append('username', element.dataset.username);
250+
form.append('content', editor.getData());
251+
252+
await fetch("/members/update/field", { method: 'POST', body: form })
253+
.then(() => {
254+
if (progress) {
255+
progress.classList.remove('u:animate-pulse', 'u:bg-bewelcome')
256+
progress.classList.add('u:hidden')
257+
}
258+
window.localStorage.removeItem(storageKey);
259+
})
260+
}
261+
}

0 commit comments

Comments
 (0)