@asd20/ui-next 2.31.6 → 2.31.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.31.8](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.31.7...ui-next-v2.31.8) (2026-10-12)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * refine 'send an email' functionality - help text, failure messaging, rate limits, spam detection ([a9c4a28](https://github.com/academydistrict20/asd20-ui-next/commit/a9c4a28f1fdab4c0c551aa2cfb6808fbc29742d2))
9
+
10
+ ## [2.31.7](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.31.6...ui-next-v2.31.7) (2026-10-12)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * update pdfservice docs; implement new email moderation for phishing ([1beb60d](https://github.com/academydistrict20/asd20-ui-next/commit/1beb60d764a8136d00773a1d81cc11a64fdc335b))
16
+
3
17
  ## [2.31.6](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.31.5...ui-next-v2.31.6) (2026-10-12)
4
18
 
5
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asd20/ui-next",
3
- "version": "2.31.6",
3
+ "version": "2.31.8",
4
4
  "private": false,
5
5
  "description": "ASD20 UI component library for Vue 3.",
6
6
  "license": "MIT",
@@ -41,7 +41,7 @@
41
41
  :validator="validateMessageBody"
42
42
  label="Message"
43
43
  maxlength="8000"
44
- help-text="Please enter at least 5 characters."
44
+ :help-text="messageHelpText"
45
45
  required
46
46
  @validated="validationErrors.messageBody = $event"
47
47
  />
@@ -124,6 +124,8 @@ import Asd20Button from '../../atoms/Asd20Button'
124
124
  import Recaptcha from '../../utils/Recaptcha'
125
125
  import sendEmail from '../../../helpers/sendEmail.js'
126
126
 
127
+ const MIN_MESSAGE_LENGTH = 10
128
+
127
129
  export default {
128
130
  name: 'Asd20ComposeEmailModal',
129
131
  components: {
@@ -161,6 +163,11 @@ export default {
161
163
  },
162
164
  }),
163
165
  computed: {
166
+ messageHelpText() {
167
+ return String(this.emailMessage.messageBody || '').trim().length < MIN_MESSAGE_LENGTH
168
+ ? 'Please provide more detail.'
169
+ : ''
170
+ },
164
171
  modalTitle() {
165
172
  return 'Send an Email'
166
173
  },
@@ -228,8 +235,8 @@ export default {
228
235
  },
229
236
  validateMessageBody({ value, validationErrors }) {
230
237
  const message = String(value || '').trim()
231
- if (message && message.length < 5)
232
- validationErrors.push('The message must be at least 5 characters.')
238
+ if (message && message.length < MIN_MESSAGE_LENGTH)
239
+ validationErrors.push('Please provide more detail.')
233
240
  return validationErrors
234
241
  },
235
242
  getFormValidationMessages() {
@@ -247,8 +254,8 @@ export default {
247
254
  messages.push('Enter a valid email address.')
248
255
  if (!subject) messages.push('A subject is required.')
249
256
  if (!messageBody) messages.push('A message is required.')
250
- else if (messageBody.length < 5)
251
- messages.push('The message must be at least 5 characters.')
257
+ else if (messageBody.length < MIN_MESSAGE_LENGTH)
258
+ messages.push('Please provide more detail.')
252
259
 
253
260
  return messages
254
261
  },
@@ -304,11 +311,25 @@ export default {
304
311
  const statusMatch = String(error?.message || '').match(/\b(\d{3})\b/)
305
312
  return statusMatch ? Number(statusMatch[1]) : null
306
313
  },
314
+ isDeliveryUnconfirmed(error) {
315
+ return this.getSendEmailResponseData(error)?.code === 'delivery_unconfirmed' || this.getSendEmailErrorStatus(error) === null
316
+ },
307
317
  getSendEmailFailureMessage(error) {
318
+ if (this.isDeliveryUnconfirmed(error)) {
319
+ return "We couldn't confirm that your message was sent. Please check with the school before sending it again."
320
+ }
308
321
  if (this.getSendEmailErrorStatus(error) === 429) {
322
+ const response = this.getSendEmailResponseData(error)
323
+ if (response?.code === 'rate_limited' && typeof response.error === 'string' && response.error.trim()) {
324
+ return response.error
325
+ }
309
326
  return 'We could not send your message right now. Please wait and try again later.'
310
327
  }
311
328
 
329
+ const response = this.getSendEmailResponseData(error)
330
+ if (['captcha_failed', 'email_unavailable'].includes(response?.code) && typeof response.error === 'string' && response.error.trim()) {
331
+ return response.error
332
+ }
312
333
  return 'Something went wrong while sending your email. Please try again later.'
313
334
  },
314
335
  getSendEmailResponseData(error) {
@@ -326,7 +347,9 @@ export default {
326
347
  },
327
348
  isModerationRejection(error) {
328
349
  return (
329
- this.getSendEmailResponseData(error)?.code === 'moderation_rejected'
350
+ ['moderation_rejected', 'moderation_unavailable'].includes(
351
+ this.getSendEmailResponseData(error)?.code
352
+ )
330
353
  )
331
354
  },
332
355
  getServerValidationMessages(error) {
@@ -339,7 +362,7 @@ export default {
339
362
  'Enter a valid email address.',
340
363
  'messageBody is required.': 'A message is required.',
341
364
  'messageBody is too short.':
342
- 'The message must be at least 5 characters.',
365
+ 'Please provide more detail.',
343
366
  'messageBody is too long.':
344
367
  'The message must be 8,000 characters or fewer.',
345
368
  'Recipient was not found or does not have a public email address.':
@@ -363,16 +386,27 @@ export default {
363
386
  }
364
387
 
365
388
  if (this.isModerationRejection(error)) {
389
+ const response = this.getSendEmailResponseData(error)
390
+ const submissionId = String(response?.submissionId || '')
391
+ const reference = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(submissionId)
392
+ ? [`Reference: ${submissionId}`]
393
+ : []
366
394
  this.showFeedback(
367
- 'Message not sent',
368
- "Your message couldn't be sent through this form.",
369
- []
395
+ response?.code === 'moderation_unavailable'
396
+ ? 'Email temporarily unavailable'
397
+ : 'Message not sent',
398
+ typeof response?.error === 'string' && response.error.trim()
399
+ ? response.error
400
+ : response?.code === 'moderation_unavailable'
401
+ ? "We couldn't send your message right now. Please try again later. If the problem persists, please contact the Academy District 20 Help Desk at help@asd20.org or 719-234-1777."
402
+ : 'Your message could not be sent through this form.',
403
+ reference
370
404
  )
371
405
  return
372
406
  }
373
407
 
374
408
  this.showFeedback(
375
- 'Email not sent',
409
+ this.isDeliveryUnconfirmed(error) ? 'Delivery not confirmed' : 'Email not sent',
376
410
  this.getSendEmailFailureMessage(error),
377
411
  []
378
412
  )