Skip to content
This repository was archived by the owner on Dec 14, 2023. It is now read-only.

Commit d5d4dd1

Browse files
authored
Merge pull request #286 from CoderDojo/bugfix/event-city
Handle issues with city data causing errors
2 parents 2a931d4 + 65356a8 commit d5d4dd1

File tree

4 files changed

+130
-37
lines changed

4 files changed

+130
-37
lines changed

src/events/cd-event-form.vue

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
<i class="fa fa-pencil pointer" @click="customAddressFormIsVisible = true" v-show="!customAddressFormIsVisible"></i>
2222
<i class="fa fa-times pointer" @click="customAddressFormIsVisible = false" v-show="customAddressFormIsVisible"></i>
2323
<div v-if="customAddressFormIsVisible">
24-
<input type="text" name="city" v-model="eventCity" class="form-control">
25-
<textarea name="address" v-model="eventAddress" rows="3" class="form-control"></textarea>
24+
<label for="city">City</label>
25+
<input id="city" type="text" name="city" v-model="eventCity" class="form-control">
26+
<label for="address">Address</label>
27+
<textarea id="address" name="address" v-model="eventAddress" rows="3" class="form-control"></textarea>
2628
</div>
2729
</div>
2830

@@ -170,7 +172,7 @@
170172
methods: {
171173
async initializeStore() {
172174
if (this.latestEvent) {
173-
EventStore.commit('setCityFromObject', this.latestEvent.city);
175+
EventStore.commit('setCityFromEventObject', this.latestEvent.city);
174176
EventStore.commit('setAddress', this.latestEvent.address);
175177
EventStore.commit('setDescription', this.latestEvent.description);
176178
EventStore.commit('generateNextEventDates',
@@ -181,7 +183,7 @@
181183
} else {
182184
EventStore.commit('setDescription', this.dojo.notes);
183185
EventStore.commit('setAddress', this.dojo.address1);
184-
EventStore.commit('setCity', this.dojo.city.name);
186+
EventStore.commit('setCity', this.dojo);
185187
}
186188
EventStore.commit('setCountry', this.dojo.country);
187189
EventStore.commit('setDojoId', this.dojo.id);
@@ -236,10 +238,10 @@
236238
},
237239
eventCity: {
238240
get() {
239-
return EventStore.getters.city;
241+
return EventStore.getters.city || '';
240242
},
241243
set(value) {
242-
EventStore.commit('setCity', value);
244+
EventStore.commit('setCity', { city: { nameWithHierarchy: value } });
243245
},
244246
},
245247
eventDescription: {

src/events/event-store.js

Lines changed: 76 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,16 @@ const store = new Vuex.Store({
55
strict: true,
66
state: {
77
eventDate: moment().format('YYYY-MM-DD'),
8-
startTime: moment.utc().add(2, 'hours').minute(0).format('HH:mm'),
9-
endTime: moment.utc().add(3, 'hours').minute(0).format('HH:mm'),
8+
startTime: moment
9+
.utc()
10+
.add(2, 'hours')
11+
.minute(0)
12+
.format('HH:mm'),
13+
endTime: moment
14+
.utc()
15+
.add(3, 'hours')
16+
.minute(0)
17+
.format('HH:mm'),
1018
event: {
1119
name: '',
1220
description: '',
@@ -24,9 +32,18 @@ const store = new Vuex.Store({
2432
notifyOnApplicant: false,
2533
sendEmails: true,
2634
newForm: true,
27-
dates: [{
28-
startTime: moment.utc().add(2, 'hours').minute(0),
29-
endTime: moment.utc().add(3, 'hours').minute(0) }],
35+
dates: [
36+
{
37+
startTime: moment
38+
.utc()
39+
.add(2, 'hours')
40+
.minute(0),
41+
endTime: moment
42+
.utc()
43+
.add(3, 'hours')
44+
.minute(0),
45+
},
46+
],
3047
sessions: [
3148
{
3249
name: 'Dojo',
@@ -55,6 +72,17 @@ const store = new Vuex.Store({
5572
delete event.position;
5673
delete event.startTime;
5774
delete event.endTime;
75+
76+
if (event.city == null) {
77+
event.city = {};
78+
}
79+
80+
// This is a workaround for '$$hashKey': 'value' in the json objects of some events.
81+
// This is something from angular tracking its props being persisted somehow.
82+
if (event.city.nameWithHierarchy) {
83+
event.city = { nameWithHierarchy: event.city.nameWithHierarchy };
84+
}
85+
5886
if (event.sessions) {
5987
event.sessions[0].tickets.forEach(t => delete t.approvedApplications);
6088
}
@@ -67,7 +95,7 @@ const store = new Vuex.Store({
6795
state.event.name = name;
6896
},
6997

70-
setCityFromObject(state, cityObject) {
98+
setCityFromEventObject(state, cityObject) {
7199
if (cityObject) {
72100
state.event.city = {
73101
nameWithHierarchy: cityObject.nameWithHierarchy || cityObject.toponymName,
@@ -83,8 +111,12 @@ const store = new Vuex.Store({
83111
state.event.description = description;
84112
},
85113

86-
setCity(state, value) {
87-
state.event.city = { nameWithHierarchy: value };
114+
setCity(state, dojo) {
115+
if (dojo.city === null || dojo.city.nameWithHierarchy === undefined) {
116+
state.event.city = {};
117+
return;
118+
}
119+
state.event.city = { nameWithHierarchy: dojo.city.nameWithHierarchy };
88120
},
89121

90122
setCountry(state, value) {
@@ -101,9 +133,12 @@ const store = new Vuex.Store({
101133
const inPast = moment().diff(newDate, 'days') > 0;
102134
if (inPast) {
103135
const neededDay = startDate.day();
104-
newDate = (moment().isoWeekday() <= neededDay) ?
105-
moment().isoWeekday(neededDay) :
106-
moment().add(1, 'weeks').isoWeekday(neededDay);
136+
newDate =
137+
moment().isoWeekday() <= neededDay
138+
? moment().isoWeekday(neededDay)
139+
: moment()
140+
.add(1, 'weeks')
141+
.isoWeekday(neededDay);
107142
}
108143

109144
state.eventDate = newDate.format('YYYY-MM-DD');
@@ -129,40 +164,56 @@ const store = new Vuex.Store({
129164
// Any event that has more than one session was created using the old form
130165
// and it is unlikely to map to the new form structure
131166
const previousTickets = event.sessions[0].tickets;
132-
const prevYouthTickets = previousTickets.find(ticket => ticket.name === 'Youth');
133-
const prevMentorTickets = previousTickets.find(ticket => ticket.name === 'Mentor');
167+
const prevYouthTickets = previousTickets.find(
168+
ticket => ticket.name === 'Youth',
169+
);
170+
const prevMentorTickets = previousTickets.find(
171+
ticket => ticket.name === 'Mentor',
172+
);
134173

135174
if (prevYouthTickets !== undefined) {
136-
const youthTickets = state.event.sessions[0].tickets
137-
.find(ticket => ticket.type === 'ninja');
175+
const youthTickets = state.event.sessions[0].tickets.find(
176+
ticket => ticket.type === 'ninja',
177+
);
138178
youthTickets.quantity = prevYouthTickets.quantity;
139179
}
140180
if (prevMentorTickets !== undefined) {
141-
const mentorTickets = state.event.sessions[0]
142-
.tickets.find(ticket => ticket.type === 'mentor');
181+
const mentorTickets = state.event.sessions[0].tickets.find(
182+
ticket => ticket.type === 'mentor',
183+
);
143184
mentorTickets.quantity = prevMentorTickets.quantity;
144185
}
145186
}
146187
},
147188

148189
updateEventDate(state, value) {
149190
state.eventDate = value;
150-
state.event.dates[0].startTime = moment.utc(`${state.eventDate} ${state.startTime}`);
151-
state.event.dates[0].endTime = moment.utc(`${state.eventDate} ${state.endTime}`);
191+
state.event.dates[0].startTime = moment.utc(
192+
`${state.eventDate} ${state.startTime}`,
193+
);
194+
state.event.dates[0].endTime = moment.utc(
195+
`${state.eventDate} ${state.endTime}`,
196+
);
152197
},
153198

154199
updateStartTime(state, value) {
155200
state.startTime = value;
156-
state.event.dates[0].startTime = moment.utc(`${state.eventDate} ${state.startTime}`);
201+
state.event.dates[0].startTime = moment.utc(
202+
`${state.eventDate} ${state.startTime}`,
203+
);
157204
},
158205

159206
updateEndTime(state, value) {
160207
state.endTime = value;
161-
state.event.dates[0].endTime = moment.utc(`${state.eventDate} ${state.endTime}`);
208+
state.event.dates[0].endTime = moment.utc(
209+
`${state.eventDate} ${state.endTime}`,
210+
);
162211
},
163212

164213
updateTicketQuantity(state, { type, quantity }) {
165-
const tickets = state.event.sessions[0].tickets.find(ticket => ticket.type === type);
214+
const tickets = state.event.sessions[0].tickets.find(
215+
ticket => ticket.type === type,
216+
);
166217
tickets.quantity = quantity;
167218
},
168219

@@ -186,7 +237,9 @@ const store = new Vuex.Store({
186237
sendEmails: state => state.event.sendEmails,
187238
// eslint-disable-next-line no-unused-vars
188239
ticketQuantity: state => (type) => {
189-
const tickets = state.event.sessions[0].tickets.find(ticket => ticket.type === type);
240+
const tickets = state.event.sessions[0].tickets.find(
241+
ticket => ticket.type === type,
242+
);
190243
return tickets.quantity;
191244
},
192245
},

test/unit/specs/events/cd-event-form.spec.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,22 +244,24 @@ describe('Event Form component', () => {
244244
it('sets event values in store from dojo', async () => {
245245
const vm = vueUnitHelper(EventFormWithMocks);
246246
vm.loggedInUser = { id: 'U1' };
247-
vm.dojo = {
247+
const dojoObject = {
248248
id: 'd1',
249249
notes: 'The dojo description notes',
250250
address1: 'Address 1 from Dojo',
251251
city: { name: 'Dojo City name' },
252252
country: { alpha2: 'GB' },
253253
};
254254

255+
vm.dojo = dojoObject;
256+
255257
await vm.initializeStore();
256258
expect(MockEventStore.commit).to.have.callCount(6);
257259
expect(MockEventStore.commit).to.have.been
258260
.calledWith('setDescription', 'The dojo description notes');
259261
expect(MockEventStore.commit).to.have.been
260262
.calledWith('setAddress', 'Address 1 from Dojo');
261263
expect(MockEventStore.commit).to.have.been
262-
.calledWith('setCity', 'Dojo City name');
264+
.calledWith('setCity', dojoObject);
263265
});
264266
});
265267
context('when latestEvent is present', () => {
@@ -281,7 +283,7 @@ describe('Event Form component', () => {
281283
await vm.initializeStore();
282284
expect(MockEventStore.commit).to.have.callCount(8);
283285
expect(MockEventStore.commit).to.have.been
284-
.calledWith('setCityFromObject', { nameWithHierarchy: 'City' });
286+
.calledWith('setCityFromEventObject', { nameWithHierarchy: 'City' });
285287
expect(MockEventStore.commit).to.have.been
286288
.calledWith('setAddress', 'Address from event');
287289
expect(MockEventStore.commit).to.have.been

test/unit/specs/events/event-store.spec.js

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,39 @@ describe('Event Store', () => {
5353
describe('mutations', () => {
5454
describe('mutations.setEvent', () => {
5555
it('sets event values correctly with default sendEmails', () => {
56-
const event = { id: 1, name: 'Event name' };
56+
const event = { id: 1, name: 'Event name', city: {} };
5757
EventStore.commit('setEvent', event);
5858

5959
expect(EventStore.state.event).to.deep.equal({
6060
id: 1,
6161
name: 'Event name',
6262
sendEmails: false,
63+
city: {},
64+
});
65+
});
66+
67+
68+
it('removes $$hashKey entries in city', () => {
69+
const event = { id: 1, name: 'Event name', city: { nameWithHierarchy: 'Newcastle upon Tyne', $$hashKey: 'object:1301' } };
70+
EventStore.commit('setEvent', event);
71+
72+
expect(EventStore.state.event).to.deep.equal({
73+
id: 1,
74+
name: 'Event name',
75+
city: { nameWithHierarchy: 'Newcastle upon Tyne' },
76+
sendEmails: false,
77+
});
78+
});
79+
80+
it('handles city being null', () => {
81+
const event = { id: 1, name: 'Event name', city: null };
82+
EventStore.commit('setEvent', event);
83+
84+
expect(EventStore.state.event).to.deep.equal({
85+
id: 1,
86+
name: 'Event name',
87+
city: {},
88+
sendEmails: false,
6389
});
6490
});
6591
});
@@ -71,16 +97,16 @@ describe('Event Store', () => {
7197
});
7298
});
7399

74-
describe('mutations.setCityFromObject', () => {
100+
describe('mutations.setCityFromEventObject', () => {
75101
context('when city object has nameWithHierarcy', () => {
76102
it('sets city correctly', () => {
77-
EventStore.commit('setCityFromObject', { nameWithHierarchy: 'Sheffield' });
103+
EventStore.commit('setCityFromEventObject', { nameWithHierarchy: 'Sheffield' });
78104
expect(EventStore.state.event.city).to.eql({ nameWithHierarchy: 'Sheffield' });
79105
});
80106
});
81107
context('when city object has toponymName', () => {
82108
it('sets city correctly', () => {
83-
EventStore.commit('setCityFromObject', { toponymName: 'Sheffield' });
109+
EventStore.commit('setCityFromEventObject', { toponymName: 'Sheffield' });
84110
expect(EventStore.state.event.city).to.eql({ nameWithHierarchy: 'Sheffield' });
85111
});
86112
});
@@ -102,9 +128,19 @@ describe('Event Store', () => {
102128

103129
describe('mutations.setCity', () => {
104130
it('sets city correctly', () => {
105-
EventStore.commit('setCity', 'Sheffield');
131+
EventStore.commit('setCity', { city: { nameWithHierarchy: 'Sheffield' } });
106132
expect(EventStore.state.event.city).to.eql({ nameWithHierarchy: 'Sheffield' });
107133
});
134+
135+
it('handles dojo city being null', () => {
136+
EventStore.commit('setCity', { city: null });
137+
expect(EventStore.state.event.city).to.eql({});
138+
});
139+
140+
it('handles dojo city being empty', () => {
141+
EventStore.commit('setCity', { city: {} });
142+
expect(EventStore.state.event.city).to.eql({});
143+
});
108144
});
109145

110146
describe('mutations.setCountry', () => {

0 commit comments

Comments
 (0)