Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript migration project (event group linker) #115

Merged
merged 2 commits into from
Oct 9, 2023
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
41 changes: 41 additions & 0 deletions public/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -405,3 +405,44 @@ article.static-page header {
margin-bottom: 1rem;
border-bottom: 1px solid #e0e0e0;
}

.card--group-preview {
display: grid;
grid-template-columns: 60px 1fr;
overflow: hidden;
gap: 1rem;

transition: background-color 0.15s;
}

.card--group-preview:hover {
background-color: #f5f5f5;
}

.card--group-preview img {
width: 100%;
height: 100%;
object-fit: cover;
}

.card--group-preview__text {
text-decoration: none;
color: #1b1b1b;
overflow: hidden;
padding-right: 1rem;
display: flex;
flex-direction: column;
justify-content: center;
}

.card--group-preview__text strong,
.card--group-preview__text p {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin: 0;
}

.card--group-preview:hover {
text-decoration: none;
}
Binary file added public/images/seigaiha-single.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions public/js/modules/event-edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ function editEventForm() {
this.data.timezone = event.target.value;
});
this.data.timezone = this.select2.val();

// Set checkboxes
this.data.eventGroupCheckbox = window.eventData.eventGroupID !== "";
this.data.interactionCheckbox = window.eventData.usersCanComment;
this.data.joinCheckbox = window.eventData.usersCanAttend;
this.data.maxAttendeesCheckbox =
window.eventData.maxAttendees !== null;
},
async submitForm() {
this.submitting = true;
Expand Down
85 changes: 85 additions & 0 deletions public/js/modules/group-linker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
function eventGroupLinker() {
return {
data: {
eventGroupID: "",
eventGroupEditToken: "",
groups: [],
},
async init() {
this.$watch("data.eventGroupID", () => {
this.$dispatch(
"event-group-id-changed",
this.data.eventGroupID,
);
});
this.$watch("data.eventGroupEditToken", () => {
this.$dispatch(
"event-group-edit-token-changed",
this.data.eventGroupEditToken,
);
});
if (window.eventData && window.eventData.eventGroupID !== "") {
this.data.eventGroupID = window.eventData.eventGroupID;
}
if (window.eventData && window.eventGroupEditToken !== "") {
this.data.eventGroupEditToken =
window.eventData.eventGroupEditToken;
}
try {
const editTokens = JSON.parse(
localStorage.getItem("editTokens"),
);
if (!editTokens) {
return;
}
const response = await fetch("/known/groups", {
method: "POST",
body: JSON.stringify(editTokens),
headers: {
"Content-Type": "application/json",
},
});
if (!response.ok) {
return;
}
const json = await (await response).json();
this.data.groups = json;
} catch (e) {
return false;
}
},
selectGroup(e) {
const group = this.data.groups.find(
(group) => group.id === e.target.value,
);
if (!group) {
this.data.eventGroupID = "";
this.data.eventGroupEditToken = "";
return;
}
this.data.eventGroupID = group.id;
this.data.eventGroupEditToken = group.editToken;
},
showGroupPreview() {
return (
this.data.eventGroupID !== "" &&
this.data.groups.some(
(group) =>
group.id === this.data.eventGroupID &&
group.editToken === this.data.eventGroupEditToken,
)
);
},
groupPreview() {
if (!this.showGroupPreview()) {
return {};
}
return this.data.groups.find(
(group) => group.id === this.data.eventGroupID,
);
},
resetGroupSelector() {
this.$refs.eventGroupSelect.value = "";
},
};
}
60 changes: 60 additions & 0 deletions src/routes/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import Jimp from "jimp";
import { addToLog } from "../helpers.js";
import EventGroup from "../models/EventGroup.js";
import { sendEmailFromTemplate } from "../lib/email.js";
import { marked } from "marked";
import { renderPlain } from "../util/markdown.js";

const config = getConfig();

Expand Down Expand Up @@ -237,4 +239,62 @@ router.put(
},
);

// Accepts a JSON object of event/group IDs mapped to edit tokens.
// Returns an object of basic group data for each of the IDs
// which are valid groups and have an edit token which matches.
router.post("/known/groups", async (req: Request, res: Response) => {
const known = req.body;
if (!known) {
return res.status(400).json({
errors: [
{
message: "No known IDs were provided.",
},
],
});
}

try {
const knownIDs = Object.keys(known);
const groups = await EventGroup.find({
id: { $in: knownIDs },
});
const knownGroups = groups.filter((group) => {
return group.editToken === known[group.id];
});
const groupData = knownGroups.map((group) => {
return {
id: group.id,
name: group.name,
description: marked
.parse(group.description, {
renderer: renderPlain(),
})
.split(" ")
.splice(0, 40)
.join(" ")
.trim(),
image: group.image,
editToken: group.editToken,
url: `/group/${group.id}`,
};
});
return res.status(200).json(groupData);
} catch (err) {
console.error(err);
addToLog(
"getKnownGroups",
"error",
"Attempt to get known groups failed with error: " + err,
);
return res.status(500).json({
errors: [
{
message: err,
},
],
});
}
});

export default router;
4 changes: 3 additions & 1 deletion views/event.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -423,9 +423,9 @@ window.eventData = {{{ json jsonData }}};
$(this).closest(".comment").find(".replyContainer").slideToggle();
})
$(document).ready(function() {

// Save the editing token from the URL, if it is valid
const eventID = $('#eventName').attr('data-event-id');
const url = new URL(window.location.href);
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('e')) {
$.ajax({
Expand Down Expand Up @@ -463,6 +463,8 @@ window.eventData = {{{ json jsonData }}};

if (urlParams.has('show_edit')) {
$('#editModal').modal('show');
url.searchParams.delete('show_edit');
history.replaceState(history.state, '', url.href);
}

// From https://davidwalsh.name/javascript-download
Expand Down
19 changes: 11 additions & 8 deletions views/eventgroup.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -229,29 +229,30 @@ window.groupData = {{{ json jsonData }}};
<script>
$(document).ready(function() {
// Save the editing token from the URL, if it is valid
const eventID = $('#eventName').attr('data-event-id');
const eventGroupID = window.groupData.id;
const url = new URL(window.location.href);
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('e')) {
$.ajax({
type: "POST",
url: `/verifytoken/group/${eventID}`,
url: `/verifytoken/group/${eventGroupID}`,
data: { editToken: urlParams.get('e') },
success: function(response, status, xhr) {
if (xhr.status === 200) {
addStoredToken(eventID, urlParams.get('e'));
addStoredToken(eventGroupID, urlParams.get('e'));
}
},
error: function(response, status, xhr) {
// The editing token is wrong - remove it
removeStoredToken(eventID);
removeStoredToken(eventGroupID);
window.location = window.location.pathname;
}
});
} else if (getStoredToken(eventID)) {
const editToken = getStoredToken(eventID);
} else if (getStoredToken(eventGroupID)) {
const editToken = getStoredToken(eventGroupID);
$.ajax({
type: "POST",
url: `/verifytoken/group/${eventID}`,
url: `/verifytoken/group/${eventGroupID}`,
data: { editToken },
success: function(response, status, xhr) {
if (xhr.status === 200) {
Expand All @@ -260,13 +261,15 @@ window.groupData = {{{ json jsonData }}};
},
error: function(response, status, xhr) {
// The editing token is wrong - remove it
removeStoredToken(eventID);
removeStoredToken(eventGroupID);
}
});
}

if (urlParams.has('show_edit')) {
$('#editModal').modal('show');
url.searchParams.delete('show_edit');
history.replaceState(history.state, '', url.href);
}

new ClipboardJS('#copyEventLink');
Expand Down
13 changes: 11 additions & 2 deletions views/newevent.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,15 @@

<div id="newEventFormContainer">
<h4 class="mb-2">Create an event</h4>
<form id="newEventForm" enctype="multipart/form-data" x-data="newEventForm()" x-init="init()" @submit.prevent="submitForm">
<form
id="newEventForm"
enctype="multipart/form-data"
x-data="newEventForm()"
x-init="init()"
@submit.prevent="submitForm"
@event-group-id-changed="data.eventGroupID = $event.detail"
@event-group-edit-token-changed="data.eventGroupEditToken = $event.detail"
>
{{>eventForm}}
<div class="form-group row">
<div class="col-sm-12 pt-3 pb-3 text-center">
Expand Down Expand Up @@ -55,4 +63,5 @@
</article>

<script src="/js/generate-timezones.js"></script>
<script src="/js/modules/new.js"></script>
<script src="/js/modules/new.js"></script>
<script src="/js/modules/group-linker.js"></script>
12 changes: 10 additions & 2 deletions views/partials/editeventmodal.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@
</button>
</div>
<div class="modal-body">
<form id="editEventForm" enctype="multipart/form-data" x-data="editEventForm()" x-init="init()"
@submit.prevent="submitForm">
<form
id="editEventForm"
enctype="multipart/form-data"
x-data="editEventForm()"
x-init="init()"
@submit.prevent="submitForm"
@event-group-id-changed="data.eventGroupID = $event.detail"
@event-group-edit-token-changed="data.eventGroupEditToken = $event.detail"
>

{{> eventForm }}

Expand Down Expand Up @@ -47,3 +54,4 @@

<script type="text/javascript" src="/js/generate-timezones.js"></script>
<script type="text/javascript" src="/js/modules/event-edit.js"></script>
<script src="/js/modules/group-linker.js"></script>
36 changes: 29 additions & 7 deletions views/partials/eventForm.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,40 @@
<div class="card-header">
<strong>Link this event to an event group</strong>
</div>
<div class="card-body">
<div class="card-body" x-data="eventGroupLinker()">
<div class="form-group-label" x-show="data.groups.length > 0">
<label>Choose a group you've edited before</label>
</div>
<div class="form-group" x-show="data.groups.length > 0">
<select x-ref="eventGroupSelect" id="eventGroupSelect" name="eventGroupSelect" class="form-control" x-on:change="selectGroup">
<option value="">Choose a group</option>
<template x-for="group in data.groups">
<option :value="group.id" x-text="group.name"></option>
</template>
</select>
</div>
<a class="card shadow-sm card--group-preview mb-3" x-show="showGroupPreview()" x-bind:href="groupPreview().url" target="_blank">
<img :src="'/events/' + groupPreview().image" x-show="groupPreview().image"/>
<img src="/images/seigaiha-single.png" x-show="!groupPreview().image"/>
<div class="card--group-preview__text">
<strong x-text="groupPreview().name"></strong>
<p x-text="groupPreview().description"></p>
</div>
</a>
<div class="alert alert-info text-center" role="alert" x-show="data.groups.length > 0">
<i class="fas fa-info-circle"></i> You can also enter the group ID and secret editing code manually.
</div>
<div class="form-group">
<label for="eventGroupID" class="col-12">Event group ID</label>
<div class="form-group col-12">
<input type="text" class="form-control" id="eventGroupID" name="eventGroupID" placeholder="" x-model="data.eventGroupID" >
<label for="eventGroupID">Event group ID</label>
<div class="form-group">
<input type="text" class="form-control" id="eventGroupID" name="eventGroupID" x-model="data.eventGroupID" x-on:input="resetGroupSelector">
<small class="form-text">You can find this short string of characters in the event group's link, in your confirmation email, or on the event group's page.</small>
</div>
</div>
<div class="form-group">
<label for="eventGroupEditToken" class="col-12">Event group secret editing code</label>
<div class="form-group col-12">
<input type="text" class="form-control" id="eventGroupEditToken" name="eventGroupEditToken" placeholder="" x-model="data.eventGroupEditToken" >
<label for="eventGroupEditToken">Event group secret editing code</label>
<div class="form-group">
<input type="text" class="form-control" id="eventGroupEditToken" name="eventGroupEditToken" x-model="data.eventGroupEditToken" x-on:input="resetGroupSelector">
<small class="form-text">You can find this long string of characters in the confirmation email you received when you created the event group.</small>
</div>
</div>
Expand Down
Loading