Split out iPad-specific wall-display configuration

This commit is contained in:
Adam Goldsmith 2022-10-12 02:10:52 -04:00
parent 7bb3bdcfdd
commit ed1392ead4
6 changed files with 182 additions and 122 deletions

84
src/common.ts Normal file
View File

@ -0,0 +1,84 @@
import { Calendar, CalendarOptions } from '@fullcalendar/core';
import iCalendarPlugin from '@fullcalendar/icalendar';
import resourceTimeGridPlugin from '@fullcalendar/resource-timegrid';
import { unique_colors } from 'unique-colors';
const calendars: { [key: string]: string } = {
computer_lab: '6mmjp85e4732ru6skf1dda54ls@group.calendar.google.com',
electronics: '1g8atbdschshrg2inf162rcqt4@group.calendar.google.com',
wood_shop: '4unv3ia1n9mc9u31n2n5lv8nd8@group.calendar.google.com',
fiber_arts_studio: '7gbndciog37ge0hd8ug33ml70k@group.calendar.google.com',
jewelry_studio: 'l0dl2jq3vhbi9f4lfmaf5negc0@group.calendar.google.com',
metal_shop: 'a4p97kiiafatqdr52c3a0cpre0@group.calendar.google.com',
room_reservations: 'f4ro53uklj2u6pr0se7ucskm6g@group.calendar.google.com',
};
const colors: string[] = unique_colors(Object.keys(calendars).length);
export const common_calendarOptions: CalendarOptions = {
schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
plugins: [iCalendarPlugin, resourceTimeGridPlugin],
allDaySlot: false,
nowIndicator: true,
headerToolbar: { start: '', center: 'title', end: '' },
initialView: 'resourceTimeGrid',
height: 'auto',
slotMinTime: '8:00',
slotMaxTime: '22:00',
businessHours: {
daysOfWeek: [0, 1, 2, 3, 4, 5, 6],
startTime: '10:00',
endTime: '21:00',
},
slotLabelFormat: {
hour: 'numeric',
minute: '2-digit',
hour12: false,
},
eventTimeFormat: {
hour: 'numeric',
minute: '2-digit',
hour12: false,
},
};
export function main(
calendarOptions: CalendarOptions,
allTools: boolean = false
) {
const calendarEl = document.getElementById('calendar');
const calendar = new Calendar(calendarEl!, calendarOptions);
Object.values(calendars).forEach((id, idx) =>
calendar.addEventSource({
url: '/calendar/ical/' + id + '/public/basic.ics',
format: 'ics',
color: colors[idx],
eventDataTransform: (eventData) => {
// clear the url to prevent clicking on the event
delete eventData.url;
const match = eventData?.title?.match(/([^\/]*) \| ([^-]*) - (.*)/);
if (match) {
const [, member, shop, tool] = match;
eventData.title = `${member}`;
eventData.resourceId = tool;
if (allTools) {
calendar.addResource({ id: tool, title: tool }, false);
}
}
return eventData;
},
})
);
calendar.render();
function refresh() {
calendar.refetchEvents();
calendar.today();
}
// refresh data every five minutes
window.setInterval(refresh, 5 * 60 * 1000);
}

View File

@ -1,107 +1,5 @@
import 'core-js/stable/url'; import { common_calendarOptions, main } from './common';
import 'core-js/stable/function';
import Intl from 'intl';
import 'intl/locale-data/jsonp/en.js';
window.Intl = Intl;
import { Calendar, CalendarOptions } from '@fullcalendar/core';
import iCalendarPlugin from '@fullcalendar/icalendar';
import resourceTimeGridPlugin from '@fullcalendar/resource-timegrid';
import { unique_colors } from 'unique-colors';
import './index.html'; import './index.html';
import './index.css';
const calendars: { [key: string]: string } = { main(common_calendarOptions);
computer_lab: '6mmjp85e4732ru6skf1dda54ls@group.calendar.google.com',
electronics: '1g8atbdschshrg2inf162rcqt4@group.calendar.google.com',
wood_shop: '4unv3ia1n9mc9u31n2n5lv8nd8@group.calendar.google.com',
fiber_arts_studio: '7gbndciog37ge0hd8ug33ml70k@group.calendar.google.com',
jewelry_studio: 'l0dl2jq3vhbi9f4lfmaf5negc0@group.calendar.google.com',
metal_shop: 'a4p97kiiafatqdr52c3a0cpre0@group.calendar.google.com',
room_reservations: 'f4ro53uklj2u6pr0se7ucskm6g@group.calendar.google.com',
};
const colors: string[] = unique_colors(Object.keys(calendars).length);
const urlParams = new URLSearchParams(window.location.search);
const toolFilter: string[] | undefined = urlParams.get('tool')?.split(';');
const calendarOptions: CalendarOptions = {
schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
plugins: [iCalendarPlugin, resourceTimeGridPlugin],
allDaySlot: false,
nowIndicator: true,
headerToolbar: { start: '', center: 'title', end: '' },
initialView: 'resourceTimeGrid',
height: 'auto',
slotMinTime: '8:00',
slotMaxTime: '22:00',
businessHours: {
daysOfWeek: [0, 1, 2, 3, 4, 5, 6],
startTime: '10:00',
endTime: '21:00',
},
slotLabelFormat: {
hour: 'numeric',
minute: '2-digit',
hour12: false,
},
eventTimeFormat: {
hour: 'numeric',
minute: '2-digit',
hour12: false,
},
resources: toolFilter
? toolFilter.map((tool) => {
return {
id: tool,
title: tool,
};
})
: [],
};
function main() {
const calendarEl = document.getElementById('calendar');
const calendar = new Calendar(calendarEl!, calendarOptions);
Object.values(calendars).forEach((id, idx) =>
calendar.addEventSource({
url: '/calendar/ical/' + id + '/public/basic.ics',
format: 'ics',
color: colors[idx],
eventDataTransform: (eventData) => {
// clear the url to prevent clicking on the event
delete eventData.url;
const match = eventData?.title?.match(/([^\/]*) \| ([^-]*) - (.*)/);
if (match) {
const [, member, shop, tool] = match;
eventData.title = `${member}`;
eventData.resourceId = tool;
if (!toolFilter) {
calendar.addResource({ id: tool, title: tool }, false);
}
}
return eventData;
},
})
);
calendar.render();
function refresh() {
calendar.refetchEvents();
calendar.today();
}
// refresh data every five minutes
window.setInterval(refresh, 5 * 60 * 1000);
}
document.body.addEventListener('touchmove', (e) => e.preventDefault(), {
passive: false,
});
main();

13
src/wall-display.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="viewport" content="initial-scale=1, user-scalable=no" />
<title>Tool Reservations</title>
</head>
<body>
<div id="calendar"></div>
<script src="bundle-wall-display.js"></script>
</body>
</html>

34
src/wall-display.ts Normal file
View File

@ -0,0 +1,34 @@
import 'core-js/stable/url';
import 'core-js/stable/function';
import Intl from 'intl';
import 'intl/locale-data/jsonp/en.js';
window.Intl = Intl;
import { CalendarOptions } from '@fullcalendar/core';
import { common_calendarOptions, main } from './common';
import './wall-display.html';
import './ios-fixes.css';
document.body.addEventListener('touchmove', (e) => e.preventDefault(), {
passive: false,
});
const urlParams = new URLSearchParams(window.location.search);
const toolFilter: string[] | undefined = urlParams.get('tool')?.split(';');
const calendarOptions: CalendarOptions = {
...common_calendarOptions,
resources: toolFilter
? toolFilter.map((tool) => {
return {
id: tool,
title: tool,
};
})
: [],
};
main(calendarOptions, !toolFilter);

View File

@ -1,8 +1,7 @@
const path = require('path'); const path = require('path');
module.exports = { const common = {
mode: 'development', mode: 'development',
entry: './src/index.ts',
devServer: { devServer: {
proxy: { proxy: {
'/calendar': { '/calendar': {
@ -11,7 +10,53 @@ module.exports = {
}, },
}, },
}, },
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.html$/i,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]',
},
},
},
],
},
devtool: 'source-map', devtool: 'source-map',
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
};
module.exports = [
{
...common,
name: 'default',
entry: './src/index.ts',
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: ['ts-loader'],
},
...common.module.rules,
],
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
},
{
...common,
name: 'wall-display',
entry: './src/wall-display.ts',
module: { module: {
rules: [ rules: [
{ {
@ -24,26 +69,12 @@ module.exports = {
exclude: /node_modules/, exclude: /node_modules/,
use: ['babel-loader', 'ts-loader'], use: ['babel-loader', 'ts-loader'],
}, },
{ ...common.module.rules,
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\/index.html$/i,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]',
},
},
},
], ],
}, },
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: { output: {
path: path.resolve(__dirname, 'dist'), path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js', filename: 'bundle-wall-display.js',
}, },
}; },
];