add compose box to email

This commit is contained in:
2024-03-09 16:41:08 -06:00
parent 35d6eba599
commit 39d1a37043
10 changed files with 231 additions and 97 deletions

6
package-lock.json generated
View File

@@ -35,6 +35,7 @@
"pug": "^3.0.2",
"sortablejs": "^1.15.0",
"teamsnap.js": "github:anthonyscorrea/teamsnap-javascript-sdk#add-eventLineup-eventLineupEntry",
"tinymce": "^6.8.3",
"underscore": "^1.13.6",
"xhr2": "^0.2.1"
},
@@ -4717,6 +4718,11 @@
"npm": ">=3.0.0"
}
},
"node_modules/tinymce": {
"version": "6.8.3",
"resolved": "https://registry.npmjs.org/tinymce/-/tinymce-6.8.3.tgz",
"integrity": "sha512-3fCHKAeqT+xNwBVESf6iDbDV0VNwZNmfrkx9c/6Gz5iB8piMfaO6s7FvoiTrj1hf1gVbfyLTnz1DooI6DhgINQ=="
},
"node_modules/to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",

View File

@@ -56,6 +56,7 @@
"pug": "^3.0.2",
"sortablejs": "^1.15.0",
"teamsnap.js": "github:anthonyscorrea/teamsnap-javascript-sdk#add-eventLineup-eventLineupEntry",
"tinymce": "^6.8.3",
"underscore": "^1.13.6",
"xhr2": "^0.2.1"
},

View File

@@ -90,6 +90,10 @@ app.use(
"/js",
express.static(path.join(__dirname, "../node_modules/sortablejs"))
);
app.use(
"/js",
express.static(path.join(__dirname, "../node_modules/tinymce"))
);
app.use(
"/js",
express.static(path.join(__dirname, "../node_modules/teamsnap.js/lib/"))

View File

@@ -11,6 +11,9 @@ exports.helpers = {
unknown: "playerUnknownCount"
}[status.toLowerCase()]
return (availabilitySummary[attribute]/availabilitySummary.team.playerMemberCount)*100.0
},
isAway: (event) => {
return event.gameType == "Away";
}
}

View File

@@ -125,8 +125,7 @@ exports.getEventLineupEmail = async (req, res)=>{
const {newEventLineupEntries} = processPostedEventLineupEntries(body, eventLineupEntries, event_lineup)
attachBenchcoachPropertiesToMember(members, newEventLineupEntries, availabilities)
members.sort(tsUtils.teamsnapMembersSortLineupAvailabilityLastName)
// eventLineup = await teamsnap.loadEventLineups(req.params.event_id)
res.status(200).render("eventlineup/email", {user, team, members, event, event_lineup, event_lineup_entries: newEventLineupEntries, availabilities, availabilitySummary})
res.status(200).render("eventlineup/partials/email_table", {user, team, members, event, event_lineup, event_lineup_entries: newEventLineupEntries, availabilities, availabilitySummary})
}
exports.getEventLineupEntries = async (req, res)=>{

View File

@@ -276,9 +276,13 @@ function emailModal(el, url) {
return Promise.reject(response.text());
}
})
.then((html) => {
email_modal.classList.add("is-open");
email_modal.querySelector(".Modal-body").innerHTML = html;
.then((lineup_table) => {
const email_textarea = document.querySelector('#email-editor')
const lineup_table_div = document.querySelector(".FieldGroup .lineup-email")
tinymce.activeEditor.setContent("Team,")
lineup_table_div.innerHTML = lineup_table
email_modal.classList.add("is-open");
// email_modal.querySelector(".Modal-body").innerHTML = html;
});
}
@@ -505,3 +509,57 @@ function toggleChildSlots (element) {
})
}
}
async function submitEmail () {
// range=document.createRange();
// window.getSelection().removeAllRanges();
// // range.selectNode(document.querySelector('.Modal').querySelector('.Modal-body'));
// tinymce.activeEditor.selection.select(tinymce.activeEditor.getBody());
// // window.getSelection().addRange(range);
// document.execCommand('copy');
// window.getSelection().removeAllRanges();
const emailStyle = `
<style>.lineup-email {
font-family: "Helvetica", sans-serif;
}
.lineup-email .title-cell {
font-weight: bold;
background-color: #323669;
color: #fff;
padding: 2px 5px;
text-transform: uppercase;
}
.lineup-email .title-cell.out {
background-color: rgb(244, 199, 195);
color: black;
}
.lineup-email .sequence-cell {
font-weight: bold;
padding: 1px 5px;
text-align: left;
}
.lineup-email .name-cell {
width: 200px;
text-align: left;
}
.lineup-email .position-label-cell {
font-weight: bold;
text-align: right;
}
.Panel .Panel {
border: none;
margin: 0;
}</style>
`
html_content = emailStyle+tinymce.activeEditor.getContent()
console.log(html_content)
navigator.clipboard.write(
[new ClipboardItem(
{
'text/plain': new Blob([tinymce.activeEditor.getContent({format: "text"})], {type: 'text/plain'}),
'text/html': new Blob([html_content], {type: 'text/html'})
})
])
}

View File

@@ -111,10 +111,19 @@
</div>
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
<script src="/js/eventlineup.js"></script>
<script src="/js/tinymce.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
colorPositions();
refreshLineup();
tinymce.init({
selector:"#email-editor",
content_css:"/css/application.css",
plugins: 'image',
menubar: false,
toolbar: 'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | outdent indent | image',
paste_data_images: true,
statusbar:false})
})
</script>

View File

@@ -1,90 +1,70 @@
<div class="lineup-email">
<table>
<thead>
<tr>
<th class="title-cell" colSpan=3>
STARTING LINEUP
</th>
</tr>
</thead>
<tbody>
{{#each members}}
{{#if (isInStartingLineup this)}}
<div>
<p>Team,</p>
<p></p>
</div>
<div>
<table>
<thead>
<tr>
<th class="title-cell" colSpan=3>
STARTING LINEUP
</th>
</tr>
</thead>
<tbody>
{{#each members}}
{{#if (isInStartingLineup this)}}
<tr>
<td class="sequence-cell">
{{plus1 this.benchcoach.eventLineupEntry.sequence}}
</td>
<td class="name-cell">{{this.lastName}}, {{this.firstName}} #{{this.jerseyNumber}}</td>
<td class="position-label-cell">{{this.benchcoach.eventLineupEntry.label}}</td>
</tr>
{{/if}}
{{/each}}
<tr>
<td class="sequence-cell">
{{plus1 this.benchcoach.eventLineupEntry.sequence}}
</td>
<td class="name-cell">{{this.lastName}}, {{this.firstName}} #{{this.jerseyNumber}}</td>
<td class="position-label-cell">{{this.benchcoach.eventLineupEntry.label}}</td>
</tr>
{{/if}}
{{/each}}
<tr>
<th class="title-cell" colSpan=3>Starting (Pos. Only)</th>
</tr>
{{#each members}}
{{#if (isInPositionOnly this)}}
<th class="title-cell" colSpan=3>Starting (Pos. Only)</th>
</tr>
{{#each members}}
{{#if (isInPositionOnly this)}}
<tr>
<td class="sequence-cell"></td>
<td class="name-cell">{{this.lastName}}, {{this.firstName}} #{{this.jerseyNumber}}</td>
<td class="position-label-cell">{{this.benchcoach.eventLineupEntry.label}}</td>
</tr>
{{/if}}
{{/each}}
<tr>
<td class="sequence-cell"></td>
<td class="name-cell">{{this.lastName}}, {{this.firstName}} #{{this.jerseyNumber}}</td>
<td class="position-label-cell">{{this.benchcoach.eventLineupEntry.label}}</td>
</tr>
{{/if}}
{{/each}}
<tr>
<th class="title-cell" colSpan=3>Subs</th>
</tr>
{{#each members}}
{{#if (isInBench this)}}
<th class="title-cell" colSpan=3>Subs</th>
</tr>
{{#each members}}
{{#if (isInBench this)}}
<tr>
<td class="sequence-cell">
{{availabilityStatusShort this.benchcoach.availability}}
</td>
<td class="name-cell">{{this.lastName}}, {{this.firstName}} #{{this.jerseyNumber}}</td>
<td class="position-label-cell">{{this.benchcoach.eventLineupEntry.label}}</td>
</tr>
{{/if}}
{{/each}}
<tr>
<td class="sequence-cell">
{{availabilityStatusShort this.benchcoach.availability}}
</td>
<td class="name-cell">{{this.lastName}}, {{this.firstName}} #{{this.jerseyNumber}}</td>
<td class="position-label-cell">{{this.benchcoach.eventLineupEntry.label}}</td>
</tr>
{{/if}}
{{/each}}
<tr>
<th class="title-cell out" colSpan=3>Out</th>
</tr>
{{#each members}}
{{#if (isInOut this)}}
<tr>
<td class="sequence-cell">
{{availabilityStatusShort this.benchcoach.availability}}
</td>
<td class="name-cell">{{this.lastName}}, {{this.firstName}} #{{this.jerseyNumber}}</td>
<td class="position-label-cell">{{this.benchcoach.eventLineupEntry.label}}</td>
</tr>
{{/if}}
{{/each}}
{{!-- <tr>
<tr>
<th>.title-cell colSpan=3 Subs
- for entry in event_lineup_entries.select{|e| e[:label].blank? and !(e[:availability_status_code] == "0" or e[:availability_status_code]== "")}
<tr>
<td>.sequence-cell
- if entry[:availability_status_code] == "1"
| YES
- if entry[:availability_status_code] == "2"
| MAY
<td>.name-cell
| #{entry[:member][:last_name]}, #{entry[:member][:first_name]} - ##{entry[:member][:jersey_number]}
<td>
<tr>
<th>.title-cell.out colSpan=3 Out
- for entry in event_lineup_entries.select{|e| e[:label].blank? and (e[:availability_status_code] == "0" or e[:availability_status_code]== "")}
<tr>
<td>.sequence-cell
- if entry[:availability_status_code] == "0"
| NO
- if entry[:availability_status_code] == ""
| UNK
<td>.name-cell
| #{entry[:member][:last_name]}, #{entry[:member][:first_name]} - ##{entry[:member][:jersey_number]}
<td> --}}
</tbody>
</table>
<th class="title-cell out" colSpan=3>Out</th>
</tr>
{{#each members}}
{{#if (isInOut this)}}
<tr>
<td class="sequence-cell">
{{availabilityStatusShort this.benchcoach.availability}}
</td>
<td class="name-cell">{{this.lastName}}, {{this.firstName}} #{{this.jerseyNumber}}</td>
<td class="position-label-cell">{{this.benchcoach.eventLineupEntry.label}}</td>
</tr>
{{/if}}
{{/each}}
</tbody>
</table>
</div>
</div>

View File

@@ -0,0 +1,62 @@
<table>
<thead>
<tr>
<th class="title-cell" colSpan=3>
STARTING LINEUP
</th>
</tr>
</thead>
<tbody>
{{#each members}}
{{#if (isInStartingLineup this)}}
<tr>
<td class="sequence-cell">
{{plus1 this.benchcoach.eventLineupEntry.sequence}}
</td>
<td class="name-cell">{{this.lastName}}, {{this.firstName}} #{{this.jerseyNumber}}</td>
<td class="position-label-cell">{{this.benchcoach.eventLineupEntry.label}}</td>
</tr>
{{/if}}
{{/each}}
<tr>
<th class="title-cell" colSpan=3>Starting (Pos. Only)</th>
</tr>
{{#each members}}
{{#if (isInPositionOnly this)}}
<tr>
<td class="sequence-cell"></td>
<td class="name-cell">{{this.lastName}}, {{this.firstName}} #{{this.jerseyNumber}}</td>
<td class="position-label-cell">{{this.benchcoach.eventLineupEntry.label}}</td>
</tr>
{{/if}}
{{/each}}
<tr>
<th class="title-cell" colSpan=3>Subs</th>
</tr>
{{#each members}}
{{#if (isInBench this)}}
<tr>
<td class="sequence-cell">
{{availabilityStatusShort this.benchcoach.availability}}
</td>
<td class="name-cell">{{this.lastName}}, {{this.firstName}} #{{this.jerseyNumber}}</td>
<td class="position-label-cell">{{this.benchcoach.eventLineupEntry.label}}</td>
</tr>
{{/if}}
{{/each}}
<tr>
<th class="title-cell out" colSpan=3>Out</th>
</tr>
{{#each members}}
{{#if (isInOut this)}}
<tr>
<td class="sequence-cell">
{{availabilityStatusShort this.benchcoach.availability}}
</td>
<td class="name-cell">{{this.lastName}}, {{this.firstName}} #{{this.jerseyNumber}}</td>
<td class="position-label-cell">{{this.benchcoach.eventLineupEntry.label}}</td>
</tr>
{{/if}}
{{/each}}
</tbody>
</table>

View File

@@ -4,13 +4,25 @@
<div onclick="javascript:this.closest('.Modal').classList.toggle('is-open')">{{{embeddedSvgFromPath "/teamsnap-ui/assets/icons/dismiss.svg" "Modal-iconDismiss"}}}</div>
<div class="Modal-header">
<div class="Modal-title">Email</div>
<div class="ButtonGroup">
<div class="Button" role="button" onclick="javascript:range=document.createRange();window.getSelection().removeAllRanges();range.selectNode(document.querySelector('.Modal').querySelector('.Modal-body')); window.getSelection().addRange(range);document.execCommand('copy');window.getSelection().removeAllRanges();">
{{{embeddedSvgFromPath "/bootstrap-icons/clipboard.svg"}}}
Copy to clipboard
</div>
</div>
<div class="Modal-body"></div>
</div>
<div class="Modal-body">
<form>
<div class="FieldGroup">
<label class="FieldGroup-label">Subject</label>
<input class="Input" type="text" value="{{dateFormat event.startDate "ddd, MMM D, YYYY h:mm A" }}, {{ event.locationName }}, ({{#if (isAway event) }}@{{/if}}{{ event.opponentName }})">
</div>
<div class="FieldGroup">
<label class="FieldGroup-label">Body</label>
<textarea id="email-editor" class="Input"></textarea>
</div>
<div class="FieldGroup">
<label class="FieldGroup-label">Lineup</label>
<div class="lineup-email"></div>
</div>
<div class="FieldGroup">
<button class="Button" role="button" onclick="submitEmail();">Submit</button>
</div>
</form>
</div>
</div>
</div>