Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 52 additions & 10 deletions cal/src/EventDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ export default {
// done loading.
const page = buildPage(evt, vm.calStart, to.fullPath);
vm.evt = evt;
// override the server's shareable with the spa's current page.
evt.shareable = window.location;
vm.$emit("pageLoaded", page);
});
}
Expand Down Expand Up @@ -92,6 +94,7 @@ export default {
const { caldaily_id } = this.$route.params;
return {
// placeholder empty event data
// 'id' will become valid when loading is finished
evt: {
caldaily_id,
},
Expand All @@ -111,15 +114,27 @@ export default {
},
loopText() {
return this.evt.loopride && 'Ride is a loop';
}
},
methods: {
webLink(evt) {
return helpers.getWebLink(evt.weburl);
},
contactLink(evt) {
return helpers.getContactLink(evt.contact);
shareableLink() {
return this.evt.shareable;
},
exportLink() {
// FIX: this matches the calendar but should be a single day.
const { series_id } = this.$route.params;
return dataPool.getExportURL(series_id);
},
addToGoogleLink() {
const { evt } = this;
return evt.id && helpers.getAddToGoogleLink(evt);
},
webLink() {
const { evt } = this;
return evt.id && helpers.getWebLink(evt.weburl);
},
contactLink() {
const { evt } = this;
return evt.id && helpers.getContactLink(evt.contact);
}
}
}
</script>
Expand All @@ -143,8 +158,8 @@ export default {
<LocationLink :evt="evt"></LocationLink>
</Term>
<Term id="organizer" label= "Organizer">
<span class="c-organizer__name c-organizer__name--link" v-if="contactLink(evt)">
<ExternalLink :href="contactLink(evt)">{{evt.organizer}}</ExternalLink>
<span class="c-organizer__name c-organizer__name--link" v-if="contactLink">
<ExternalLink :href="contactLink">{{evt.organizer}}</ExternalLink>
</span>
<span v-else class="c-organizer__name c-organizer__name--text">
{{ evt.organizer }}
Expand All @@ -162,14 +177,19 @@ export default {
<Term id="locend" label= "End Location" pretext="Ending at " :text="evt.locend"/>
<Term id="loop" label= "Loop" :text="loopText"/>
<Term v-if="evt.weburl" label="More Info">
<ExternalLink :href="webLink(evt)">
<ExternalLink :href="webLink">
{{evt.webname || evt.weburl}}
</ExternalLink>
</Term>
</dl>
<p class="c-description">
{{evt.details}}
</p>
<ul class="c-detail-links" v-if="evt.id">
<li><a :href="shareableLink" class="c-links__share" rel="bookmark">Sharable link</a></li>
<li><a :href="exportLink" class="c-links__export">Export to calendar</a></li>
<li><a :href="addToGoogleLink" class="c-links__google" target="_blank">Add to Google Calendar</a></li>
</ul>
</article>
</template>

Expand Down Expand Up @@ -205,4 +225,26 @@ export default {
margin-top: 1em;
padding-top: 1em;
}
.c-detail-links {
display: flex;
justify-content: center;
flex-direction: column;
flex-flow: row wrap;
list-style-type: none;
gap: 5px;
/* on safari empty tags collapse, on chrome they take up space.
this helps keep things consistent */
margin: 1em 0;
padding-inline-start: 0px;

/* copied from main.css eventlink */
li {
border-right: 1px solid var(--page-text);
padding-right: 5px;
&:last-child {
border-right: none;
}
}
}

</style>
30 changes: 30 additions & 0 deletions cal/src/calHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,36 @@ export default {
return friendlyTime(time) + suffix;
},

// duplicated from calendars helpers
getAddToGoogleLink(event) {
const googleCalUrl = new URL('https://www.google.com/calendar/render');

const startDate = dayjs(`${event.date} ${event.time}`).toISOString();
const duration = event.duration ?? 60; // Google requires a duration and defaults to 60 minutes anyway
const endDate = dayjs(startDate).add(dayjs.duration({ 'minute': duration })).toISOString();
/**
* Matches anything that is not a word or whitespace
* @example
* "2025-05-21T16:30:00.000Z".replace(regex, '') // 20250521T163000000Z
*/
const regex = /[^\w\s]/gi;

// Remove colons and periods for Google Calendar URL (2025-05-21T16:30:00.000Z => 20250521T163000000Z)
const calendarDates = `${startDate.replace(regex, '')}/${endDate.replace(regex, '')}`;

googleCalUrl.search = new URLSearchParams({
action: "TEMPLATE",
text: `shift2Bikes: ${event.title}`,
location: event.address,
details: `${event.details}\n\n${event.shareable}`,
dates: calendarDates,
sf: true, // ??
output: 'xml'
});

return googleCalUrl.toString();
},

// https://jasonwatmore.com/vanilla-js-slugify-a-string-in-javascript
// might want the server to do this; but fine for now.
slugify(evt) {
Expand Down
1 change: 0 additions & 1 deletion cal/src/eventDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ function buildShortcuts(evt, fullPath) {
};
},
addevent: "/addevent/",
export: `/api/ics.php?id=${evt.id}`,
// hide share till its ready
// see also the ShortcutButton
// this might depend on platform or sussing out capabilities.
Expand Down
2 changes: 2 additions & 0 deletions cal/src/siteConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import siteInfo from 'extras/siteInfo.json'
import dayjs from 'dayjs'
import advancedFormat from 'dayjs/plugin/advancedFormat'
import customParseFormat from 'dayjs/plugin/customParseFormat'
import duration from 'dayjs/plugin/duration'

dayjs.extend(advancedFormat);
dayjs.extend(customParseFormat);
dayjs.extend(duration);

// the calendar part of the menu has links to the pages we are already on
// so those are unneeded.
Expand Down
9 changes: 8 additions & 1 deletion cal/src/support/dataPool.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const API_BASE_URL = window.location.origin;
// const API_BASE_URL = "https://api.shift2bikes.org";
const API_EVENTS_URL = new URL(`/api/events.php`, API_BASE_URL);
const API_SEARCH_URL = new URL(`/api/search.php`, API_BASE_URL);
const API_ICS_URL = new URL('/api/ics.php', API_BASE_URL);

// cache the most recent range.
// useful for front-end development where browser caching is disable.
Expand Down Expand Up @@ -73,7 +74,13 @@ export default {
const data = await resp.json(); // data => { events: [], pagination: {} }
mungeEvents(data.events);
return data;
}
},
// fix: this isn't nice as a method of data pool
// make an endpoints file of some sort that dataPool uses.
// ( and then have callers of this use that file directly )
getExportURL(id) {
return buildUrl(API_ICS_URL, {id});
},
}

// change dates into dayjs; and sort.
Expand Down