@@ -142,19 +142,31 @@ export default class Checkin extends Command {
142142
143143 // Now we finally check the command argument.
144144 // If we just had `checkin` in our call, no arguments...
145- const asAttendanceForm = this . client . settings . asAttendanceForm ;
145+ const { asAttendanceForm } = this . client . settings ;
146146 if ( ! isPublic ) {
147147 const author = await this . client . users . fetch ( interaction . member ! . user . id ) ;
148148 // What we need now is to construct the Payload to send for `checkin`.
149- const privateMessage = await Checkin . getCheckinMessage ( todayEvents , isPublic , needsSlide , needsASForm , asAttendanceForm ) ;
149+ const privateMessage = await Checkin . getCheckinMessage (
150+ todayEvents ,
151+ isPublic ,
152+ needsSlide ,
153+ needsASForm ,
154+ asAttendanceForm
155+ ) ;
150156 await author . send ( privateMessage ) ;
151157 await super . edit ( interaction , {
152158 content : 'Check your DM.' ,
153159 ephemeral : true ,
154160 } ) ;
155161 await interaction . followUp ( `**/checkin** was used privately by ${ interaction . user } !` ) ;
156162 } else {
157- const publicMessage = await Checkin . getCheckinMessage ( todayEvents , isPublic , needsSlide , needsASForm , asAttendanceForm ) ;
163+ const publicMessage = await Checkin . getCheckinMessage (
164+ todayEvents ,
165+ isPublic ,
166+ needsSlide ,
167+ needsASForm ,
168+ asAttendanceForm
169+ ) ;
158170 await super . edit ( interaction , publicMessage ) ;
159171 }
160172 } catch ( e ) {
@@ -182,8 +194,7 @@ export default class Checkin extends Command {
182194 * @private
183195 */
184196 private async getFutureEvents ( ) : Promise < PortalEvent [ ] > {
185- try {
186- const portalAPIResponse = ( await got ( `${ this . client . settings . portalAPI . url } /event/future` , {
197+ const portalAPIResponse = ( await got ( `${ this . client . settings . portalAPI . url } /event/future` , {
187198 headers : {
188199 'Content-Type' : 'application/json' ,
189200 Authorization : `Bearer ${ this . client . apiToken } ` ,
@@ -194,10 +205,6 @@ export default class Checkin extends Command {
194205 start : DateTime . fromISO ( event . start ) ,
195206 end : DateTime . fromISO ( event . end ) ,
196207 } ) ) ;
197- } catch ( error ) {
198- console . error ( 'API request failed: ' , error ) ;
199- throw error ;
200- }
201208 }
202209
203210 /**
@@ -209,16 +216,21 @@ export default class Checkin extends Command {
209216 * @param needsSlide whether or not we're generating a widesgreen slide graphic
210217 * @returns URL of the generated QR code.
211218 */
212- private static async generateQRCodeURL ( event : PortalEvent , expressCheckinURL : URL , needsASForm : boolean , asFormFilledURL : URL , needsSlide : boolean ) {
219+ private static async generateQRCodeURL (
220+ event : PortalEvent ,
221+ expressCheckinURL : URL ,
222+ needsASForm : boolean ,
223+ asFormFilledURL : URL ,
224+ needsSlide : boolean
225+ ) {
213226 // Doesn't need landscape QR slide. Return the QR code by itself
214227 let qrCodeDataUrl ;
215228 if ( needsSlide ) {
216229 const eventQrCode = QR . generateQR ( expressCheckinURL . toString ( ) , '' , '' , 'acm' ) ;
217- if ( needsASForm ) {
230+ if ( needsASForm ) {
218231 const asFormQrCode = QR . generateQR ( asFormFilledURL . toString ( ) , '' , '' , 'as' ) ;
219232 qrCodeDataUrl = await this . createQRSlide ( event , eventQrCode , asFormQrCode ) ;
220- }
221- else {
233+ } else {
222234 qrCodeDataUrl = await this . createQRSlide ( event , eventQrCode ) ;
223235 }
224236 } else {
@@ -232,6 +244,7 @@ export default class Checkin extends Command {
232244
233245 return qrCodeDataUrl ;
234246 }
247+
235248 /**
236249 * Creates a slide with the given QR Code and returns its URL.
237250 * @param event Portal Event to create the slide for.
@@ -241,10 +254,10 @@ export default class Checkin extends Command {
241254 */
242255 private static async createQRSlide ( event : PortalEvent , eventQrCode : string , asFormQrCode ?: string ) {
243256 /**
244- * Rescales the font; makes the font size smaller if the text is longer
245- * and bigger if the text is shorter.
246- * @param size Original font size before rescaling
247- */
257+ * Rescales the font; makes the font size smaller if the text is longer
258+ * and bigger if the text is shorter.
259+ * @param size Original font size before rescaling
260+ */
248261 const rescaleFont = ( size : number , min : number , max : number ) => {
249262 // We want to limit how small or how big the font can get
250263 let rescaledSize = size ;
@@ -267,7 +280,7 @@ export default class Checkin extends Command {
267280 context . fillRect ( 0 , 0 , 1920 , 1280 ) ;
268281
269282 // AS attendance form and ACM portal checkin both needed — use dual layout
270- if ( typeof asFormQrCode !== undefined && asFormQrCode ) {
283+ if ( typeof asFormQrCode !== ' undefined' && asFormQrCode ) {
271284 // Draw background
272285 const background = await loadImage ( './src/assets/dual-qr-slide-background.png' ) ;
273286 context . drawImage ( background , 0 , 0 , 1920 , 1280 ) ;
@@ -321,65 +334,64 @@ export default class Checkin extends Command {
321334
322335 // Get the Data URL of the image (base-64 encoded string of image).
323336 // Easier to attach than saving files.
324- return await slide . toDataURL ( ) ;
337+ return slide . toDataURL ( ) ;
325338 }
326339 // Only ACM portal checkin needed
327- else {
328- // Draw background
329- const background = await loadImage ( './src/assets/qr-slide-background.png' ) ;
330- context . drawImage ( background , 0 , 0 , 1920 , 1080 ) ;
331-
332- // Draw QR code
333- // Tilting the slide 45 degrees before adding QR code
334- const angleInRadians = Math . PI / 4 ;
335- context . rotate ( angleInRadians ) ;
336- const qrImg = await loadImage ( await eventQrCode ) ;
337- context . drawImage ( qrImg , 375 , - 325 , 600 , 600 ) ;
338- context . rotate ( - 1 * angleInRadians ) ;
339-
340- // Everything starting here has a shadow
341- context . shadowColor = '#00000040' ;
342- context . shadowBlur = 4 ;
343- context . shadowOffsetY = 4 ;
344-
345- // Event title
346- const title =
347- event . title . substring ( 0 , 36 ) === event . title ? event . title : event . title . substring ( 0 , 36 ) . concat ( '...' ) ;
348- const titleSize = rescaleFont ( title . length , 8 , 70 ) ;
349- context . textAlign = 'center' ;
350- context . font = `${ titleSize } pt 'DM Sans'` ;
351- context . fillText ( title , 1400 , 550 ) ;
352340
353- // Everything starting here has a shadow
354- context . shadowColor = '#00000040' ;
355- context . shadowBlur = 6.5 ;
356- context . shadowOffsetY = 6.5 ;
357-
358- // Code
359- const checkinCode = event . attendanceCode ;
360- const checkinSize = rescaleFont ( checkinCode . length , 30 , 70 ) ;
361- context . fillStyle = '#ffffff' ;
362- context . font = `${ checkinSize } pt 'DM Sans'` ;
363- const textMetrics = context . measureText ( checkinCode ) ;
364- let codeWidth = textMetrics . actualBoundingBoxLeft + textMetrics . actualBoundingBoxRight ;
365- // Add 120 for padding on left and right side
366- codeWidth += 120 ;
367- context . fillStyle = '#70BAFF' ;
368- context . beginPath ( ) ;
369- // roundRect parameters: x, y, width, height, radius
370- context . roundRect ( 1400 - codeWidth / 2 , 620 , codeWidth , 136 , 20 ) ;
371- context . fill ( ) ;
372- context . shadowOffsetY = 6.62 ;
373- context . font = `${ checkinSize } pt 'DM Sans'` ;
374- context . fillStyle = '#fff' ;
375- context . fillText ( checkinCode , 1400 , 710 ) ;
376-
377- // Get the Data URL of the image (base-64 encoded string of image).
378- // Easier to attach than saving files.
379- const qrCodeDataUrl = await slide . toDataURL ( ) ;
380- return qrCodeDataUrl ;
381- }
341+ // Draw background
342+ const background = await loadImage ( './src/assets/qr-slide-background.png' ) ;
343+ context . drawImage ( background , 0 , 0 , 1920 , 1080 ) ;
344+
345+ // Draw QR code
346+ // Tilting the slide 45 degrees before adding QR code
347+ const angleInRadians = Math . PI / 4 ;
348+ context . rotate ( angleInRadians ) ;
349+ const qrImg = await loadImage ( await eventQrCode ) ;
350+ context . drawImage ( qrImg , 375 , - 325 , 600 , 600 ) ;
351+ context . rotate ( - 1 * angleInRadians ) ;
352+
353+ // Everything starting here has a shadow
354+ context . shadowColor = '#00000040' ;
355+ context . shadowBlur = 4 ;
356+ context . shadowOffsetY = 4 ;
357+
358+ // Event title
359+ const title =
360+ event . title . substring ( 0 , 36 ) === event . title ? event . title : event . title . substring ( 0 , 36 ) . concat ( '...' ) ;
361+ const titleSize = rescaleFont ( title . length , 8 , 70 ) ;
362+ context . textAlign = 'center' ;
363+ context . font = `${ titleSize } pt 'DM Sans'` ;
364+ context . fillText ( title , 1400 , 550 ) ;
365+
366+ // Everything starting here has a shadow
367+ context . shadowColor = '#00000040' ;
368+ context . shadowBlur = 6.5 ;
369+ context . shadowOffsetY = 6.5 ;
370+
371+ // Code
372+ const checkinCode = event . attendanceCode ;
373+ const checkinSize = rescaleFont ( checkinCode . length , 30 , 70 ) ;
374+ context . fillStyle = '#ffffff' ;
375+ context . font = `${ checkinSize } pt 'DM Sans'` ;
376+ const textMetrics = context . measureText ( checkinCode ) ;
377+ let codeWidth = textMetrics . actualBoundingBoxLeft + textMetrics . actualBoundingBoxRight ;
378+ // Add 120 for padding on left and right side
379+ codeWidth += 120 ;
380+ context . fillStyle = '#70BAFF' ;
381+ context . beginPath ( ) ;
382+ // roundRect parameters: x, y, width, height, radius
383+ context . roundRect ( 1400 - codeWidth / 2 , 620 , codeWidth , 136 , 20 ) ;
384+ context . fill ( ) ;
385+ context . shadowOffsetY = 6.62 ;
386+ context . font = `${ checkinSize } pt 'DM Sans'` ;
387+ context . fillStyle = '#fff' ;
388+ context . fillText ( checkinCode , 1400 , 710 ) ;
389+
390+ // Get the Data URL of the image (base-64 encoded string of image).
391+ // Easier to attach than saving files.
392+ return slide . toDataURL ( ) ;
382393 }
394+
383395 /**
384396 * Generate the payload for a Checkin Code Embed with the provided list of PortalEvents,
385397 * adding QR code attachments if necessary.
@@ -401,7 +413,7 @@ export default class Checkin extends Command {
401413 isPublic : boolean ,
402414 needsSlide : boolean ,
403415 needsASForm : boolean ,
404- asAttendanceForm : string ,
416+ asAttendanceForm : string
405417 ) : Promise < InteractionPayload > {
406418 // This method became very complicated very quickly, so we'll break this down.
407419 // Create arrays to store our payload contents temporarily. We'll put this in our embed
@@ -421,8 +433,8 @@ export default class Checkin extends Command {
421433 const expressCheckinURL = new URL ( 'https://members.acmucsd.com/checkin' ) ;
422434 expressCheckinURL . searchParams . set ( 'code' , event . attendanceCode ) ;
423435
424- const asFormFilledURL = new URL ( asAttendanceForm + event . title . replace ( ' ' , '+' ) )
425- // +'&entry.570464428='+event.foodItems.replace(' ', '+') — for food items
436+ const asFormFilledURL = new URL ( asAttendanceForm + event . title . replace ( ' ' , '+' ) ) ;
437+ // +'&entry.570464428='+event.foodItems.replace(' ', '+') — for food items
426438
427439 // Add the Event's title and make it a hyperlink to the express check-in URL.
428440 description . push ( `*[${ event . title } ](${ expressCheckinURL } )*` ) ;
@@ -432,7 +444,13 @@ export default class Checkin extends Command {
432444 description . push ( '\n' ) ;
433445
434446 try {
435- const qrCodeDataUrl = await this . generateQRCodeURL ( event , expressCheckinURL , needsASForm , asFormFilledURL , needsSlide ) ;
447+ const qrCodeDataUrl = await this . generateQRCodeURL (
448+ event ,
449+ expressCheckinURL ,
450+ needsASForm ,
451+ asFormFilledURL ,
452+ needsSlide
453+ ) ;
436454 // Do some Discord.js shenanigans to generate an attachment from the image.
437455 // Apparently, the Data URL MIME type of an image needs to be removed before given to
438456 // Discord.js. Probably because the base64 encode is enough,
0 commit comments