@asd20/ui-next 2.31.7 → 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,12 @@
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
+
3
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)
4
11
 
5
12
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asd20/ui-next",
3
- "version": "2.31.7",
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) {
@@ -341,7 +362,7 @@ export default {
341
362
  'Enter a valid email address.',
342
363
  'messageBody is required.': 'A message is required.',
343
364
  'messageBody is too short.':
344
- 'The message must be at least 5 characters.',
365
+ 'Please provide more detail.',
345
366
  'messageBody is too long.':
346
367
  'The message must be 8,000 characters or fewer.',
347
368
  'Recipient was not found or does not have a public email address.':
@@ -374,15 +395,18 @@ export default {
374
395
  response?.code === 'moderation_unavailable'
375
396
  ? 'Email temporarily unavailable'
376
397
  : 'Message not sent',
377
- response?.error ||
378
- "We couldn't send your message through this form. For assistance contacting the appropriate staff member, please contact the Academy District 20 Help Desk at help@asd20.org or 719-234-1777.",
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.',
379
403
  reference
380
404
  )
381
405
  return
382
406
  }
383
407
 
384
408
  this.showFeedback(
385
- 'Email not sent',
409
+ this.isDeliveryUnconfirmed(error) ? 'Delivery not confirmed' : 'Email not sent',
386
410
  this.getSendEmailFailureMessage(error),
387
411
  []
388
412
  )