Skip to content

Commit 74df79e

Browse files
jeremymanningclaude
andcommitted
Add per-type locations, location override, and event label support
Walk and Grab coffee types: in-person only (no Zoom), location override "Meet at Jeremy's office — Moore 349", and custom event titles ("Name/Jeremy walk", "Name/Jeremy coffee"). - meeting-types.yaml: allowed_locations, location_override, event_label - booking-form.js: updateLocations() filters format dropdown per type - app.js: applies location_override and passes eventLabel to backend - Code.gs/Booking.gs: stores eventLabel, uses it in calendar event title Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 1a89585 commit 74df79e

5 files changed

Lines changed: 54 additions & 4 deletions

File tree

backend/Booking.gs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
var BookingStore = (function () {
77
var HEADERS = [
88
'token', 'tokenExpiresAt', 'eventId', 'status', 'meetingTypeId',
9-
'meetingTypeName', 'startTime', 'endTime', 'firstName', 'lastName',
9+
'meetingTypeName', 'eventLabel', 'startTime', 'endTime', 'firstName', 'lastName',
1010
'email', 'format', 'location', 'purpose', 'notes', 'createdAt',
1111
'cancelledAt', 'rescheduledTo',
1212
];

backend/Code.gs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,9 @@ function handleCreateBooking(data) {
159159
// Create calendar event
160160
var ownerName = Config.get('OWNER_NAME') || 'Jeremy';
161161
var ownerFirst = ownerName.split(' ')[0];
162-
var eventTitle = data.firstName + '/' + ownerFirst + ': ' + data.meetingTypeName;
162+
var eventTitle = data.eventLabel
163+
? data.firstName + '/' + ownerFirst + ' ' + data.eventLabel
164+
: data.firstName + '/' + ownerFirst + ': ' + data.meetingTypeName;
163165
var description = buildEventDescription(data);
164166
var calendar = CalendarApp.getCalendarById(Config.get('CALENDAR_ID'));
165167
var event = calendar.createEvent(eventTitle, startDate, endDate, {
@@ -175,6 +177,7 @@ function handleCreateBooking(data) {
175177
status: 'confirmed',
176178
meetingTypeId: data.meetingTypeId,
177179
meetingTypeName: data.meetingTypeName,
180+
eventLabel: data.eventLabel || '',
178181
startTime: data.start,
179182
endTime: data.end,
180183
firstName: data.firstName,
@@ -357,7 +360,9 @@ function handleRescheduleBooking(data) {
357360
};
358361
var ownerName = Config.get('OWNER_NAME') || 'Jeremy';
359362
var ownerFirst = ownerName.split(' ')[0];
360-
var eventTitle = oldBooking.firstName + '/' + ownerFirst + ': ' + oldBooking.meetingTypeName;
363+
var eventTitle = oldBooking.eventLabel
364+
? oldBooking.firstName + '/' + ownerFirst + ' ' + oldBooking.eventLabel
365+
: oldBooking.firstName + '/' + ownerFirst + ': ' + (oldBooking.meetingTypeName || oldBooking.meetingTypeId);
361366
var description = buildEventDescription(descData);
362367
var calendar = CalendarApp.getCalendarById(Config.get('CALENDAR_ID'));
363368
var newEvent = calendar.createEvent(eventTitle, newStart, newEnd, {
@@ -374,6 +379,7 @@ function handleRescheduleBooking(data) {
374379
status: 'confirmed',
375380
meetingTypeId: oldBooking.meetingTypeId,
376381
meetingTypeName: oldBooking.meetingTypeName || oldBooking.meetingTypeId,
382+
eventLabel: oldBooking.eventLabel || '',
377383
startTime: data.newStart,
378384
endTime: data.newEnd,
379385
firstName: oldBooking.firstName,

config/meeting-types.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,17 @@ meeting_types:
1717
name: "Walk"
1818
description: "Go for a walk and talk."
1919
allowed_durations: [30, 45, 60]
20+
allowed_locations: ["in-person"]
21+
location_override: "Meet at Jeremy's office — Moore 349"
22+
event_label: "walk"
2023

2124
- id: grab-coffee
2225
name: "Grab coffee"
2326
description: "Grab a coffee and chat."
2427
allowed_durations: [30, 45, 60]
28+
allowed_locations: ["in-person"]
29+
location_override: "Meet at Jeremy's office — Moore 349"
30+
event_label: "coffee"
2531

2632
- id: other
2733
name: "Other"

js/app.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ var App = (function () {
175175
TimezoneUtil.formatDateTime(slot.start) + ' (' +
176176
TimezoneUtil.getTimezoneAbbreviation() + ')';
177177

178+
// Filter location dropdown based on type's allowed_locations
179+
BookingForm.updateLocations(_selectedType.allowed_locations || null);
180+
178181
// Show or hide instruction banner
179182
var banner = document.getElementById('instruction-banner');
180183
if (_selectedType.instructions) {
@@ -265,17 +268,24 @@ var App = (function () {
265268
return loc.id === formData.format;
266269
});
267270

271+
// Apply location_override if the meeting type specifies one
272+
var locationValue = location ? location.value : formData.format;
273+
if (_selectedType.location_override) {
274+
locationValue = _selectedType.location_override;
275+
}
276+
268277
var bookingData = {
269278
meetingTypeId: _selectedType.id,
270279
meetingTypeName: _selectedType.name,
280+
eventLabel: _selectedType.event_label || '',
271281
duration: _selectedDuration,
272282
start: _selectedSlot.start,
273283
end: _selectedSlot.end,
274284
firstName: formData.firstName,
275285
lastName: formData.lastName,
276286
email: formData.email,
277287
format: formData.format,
278-
location: location ? location.value : formData.format,
288+
location: locationValue,
279289
purpose: formData.purpose || '',
280290
notes: formData.notes || '',
281291
};

js/booking-form.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,39 @@ var BookingForm = (function () {
150150
return map[name] || name;
151151
}
152152

153+
/**
154+
* Re-populate the format dropdown, optionally filtering to only allowed location IDs.
155+
* If allowedIds is null/undefined, shows all locations.
156+
*/
157+
function updateLocations(allowedIds) {
158+
var filtered = _locations;
159+
if (allowedIds && allowedIds.length > 0) {
160+
filtered = _locations.filter(function (loc) {
161+
return allowedIds.indexOf(loc.id) !== -1;
162+
});
163+
}
164+
var select = document.getElementById('format');
165+
while (select.options.length > 1) {
166+
select.remove(1);
167+
}
168+
filtered.forEach(function (loc) {
169+
var option = document.createElement('option');
170+
option.value = loc.id;
171+
option.textContent = loc.label;
172+
select.appendChild(option);
173+
});
174+
// Auto-select if only one option
175+
if (filtered.length === 1) {
176+
select.value = filtered[0].id;
177+
}
178+
}
179+
153180
return {
154181
init: init,
155182
validateField: validateField,
156183
validateAll: validateAll,
157184
extractFormData: extractFormData,
185+
updateLocations: updateLocations,
158186
};
159187
})();
160188

0 commit comments

Comments
 (0)