@asd20/ui-next 2.6.0 → 2.7.1

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.7.1](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.7.0...ui-next-v2.7.1) (2026-05-05)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * allow compose email modal to interpret AI rejection code ([411c383](https://github.com/academydistrict20/asd20-ui-next/commit/411c38300678a57c4eec6c5892206089b359202d))
9
+
10
+ # [2.7.0](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.6.0...ui-next-v2.7.0) (2026-05-05)
11
+
12
+
13
+ ### Features
14
+
15
+ * implement AI evaluation of email messages ([4ed90b4](https://github.com/academydistrict20/asd20-ui-next/commit/4ed90b413da2b2690b3655c1c701003cbdbb7bd6))
16
+
3
17
  # [2.6.0](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.5.0...ui-next-v2.6.0) (2026-05-04)
4
18
 
5
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asd20/ui-next",
3
- "version": "2.6.0",
3
+ "version": "2.7.1",
4
4
  "private": false,
5
5
  "description": "ASD20 UI component library for Vue 3.",
6
6
  "license": "MIT",
@@ -92,6 +92,7 @@ $input-focus-color: var(--color__accent-t50);
92
92
  color: var(--website-card__reverse-background-color);
93
93
  border: 2px solid var(--color__accent);
94
94
  border-radius: 0;
95
+ font-family: var(--website-typography__font-family-body);
95
96
  font-size: 1rem;
96
97
  line-height: 1;
97
98
  padding: space(0.25) space(0.25);
@@ -87,6 +87,7 @@ $input-focus-color: var(--color__accent-t50);
87
87
  color: var(--website-card__reverse-background-color);
88
88
  border: 2px solid var(--color__accent);
89
89
  border-radius: 0;
90
+ font-family: var(--website-typography__font-family-body);
90
91
  font-size: 1rem;
91
92
  line-height: 1;
92
93
  padding: space(0.25) space(0.25);
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <asd20-modal
3
3
  :open="open"
4
- title="Send an Email"
4
+ :title="modalTitle"
5
5
  icon="email"
6
6
  dismissable
7
7
  windowed
@@ -9,59 +9,90 @@
9
9
  @dismiss="$emit('dismiss')"
10
10
  >
11
11
  <Asd20Viewport scrollable>
12
- <asd20-text-input
13
- id="senderName"
14
- v-model="emailMessage.senderName"
15
- label="Your Full Name"
16
- required
17
- @validated="validationErrors.senderName = $event"
18
- />
19
- <asd20-text-input
20
- id="senderEmail"
21
- v-model="emailMessage.senderEmail"
22
- type="email"
23
- :validator="validateEmailAddress"
24
- label="Your Email Address"
25
- required
26
- @validated="validationErrors.senderEmail = $event"
27
- />
28
- <asd20-text-area-input
29
- id="messageBody"
30
- v-model="emailMessage.messageBody"
31
- label="Message"
32
- required
33
- @validated="validationErrors.messageBody = $event"
34
- />
12
+ <template v-if="!sendRejected">
13
+ <asd20-text-input
14
+ id="senderName"
15
+ v-model="emailMessage.senderName"
16
+ label="Your Full Name"
17
+ required
18
+ @validated="validationErrors.senderName = $event"
19
+ />
20
+ <asd20-text-input
21
+ id="senderEmail"
22
+ v-model="emailMessage.senderEmail"
23
+ type="email"
24
+ :validator="validateEmailAddress"
25
+ label="Your Email Address"
26
+ required
27
+ @validated="validationErrors.senderEmail = $event"
28
+ />
29
+ <asd20-text-area-input
30
+ id="messageBody"
31
+ v-model="emailMessage.messageBody"
32
+ label="Message"
33
+ required
34
+ @validated="validationErrors.messageBody = $event"
35
+ />
36
+ <div
37
+ class="asd20-compose-email-modal__submit"
38
+ aria-live="polite"
39
+ >
40
+ <Recaptcha
41
+ v-if="!sending && !sendSucceeded"
42
+ sitekey="6LfidKoUAAAAAFqr3QEbia3jIkecsZyxBYlMvWrX"
43
+ :load-recaptcha-script="true"
44
+ size="invisible"
45
+ @verify="captchaVerified"
46
+ >
47
+ <asd20-button
48
+ :disabled="!isValid"
49
+ label="Send"
50
+ horizontal
51
+ centered
52
+ bordered
53
+ />
54
+ </Recaptcha>
55
+ <asd20-spinner
56
+ v-else-if="sending"
57
+ size="sm"
58
+ />
59
+ <p
60
+ v-else
61
+ class="asd20-compose-email-modal__success"
62
+ role="status"
63
+ >
64
+ Your message was sent.
65
+ </p>
66
+ </div>
67
+ </template>
35
68
  <div
36
- class="asd20-compose-email-modal__submit"
37
- aria-live="polite"
69
+ v-else
70
+ class="asd20-compose-email-modal__rejection"
71
+ role="status"
38
72
  >
39
- <Recaptcha
40
- v-if="!sending && !sendSucceeded"
41
- sitekey="6LfidKoUAAAAAFqr3QEbia3jIkecsZyxBYlMvWrX"
42
- :load-recaptcha-script="true"
43
- size="invisible"
44
- @verify="captchaVerified"
73
+ <p
74
+ class="asd20-compose-email-modal__rejection-message"
45
75
  >
76
+ Please contact the Academy District 20 Help Desk who can evaluate your
77
+ request and route it appropriately.
78
+ </p>
79
+ <div class="asd20-compose-email-modal__rejection-actions">
46
80
  <asd20-button
47
- :disabled="!isValid"
48
- label="Send"
81
+ label="Contact Our Help Desk"
82
+ :link="helpDeskUrl"
49
83
  horizontal
50
84
  centered
51
85
  bordered
52
86
  />
53
- </Recaptcha>
54
- <asd20-spinner
55
- v-else-if="sending"
56
- size="sm"
57
- />
58
- <p
59
- v-else
60
- class="asd20-compose-email-modal__success"
61
- role="status"
62
- >
63
- Your message was sent.
64
- </p>
87
+ <asd20-button
88
+ label="Cancel"
89
+ horizontal
90
+ centered
91
+ bordered
92
+ transparent
93
+ @click="$emit('dismiss')"
94
+ />
95
+ </div>
65
96
  </div>
66
97
  </Asd20Viewport>
67
98
  </asd20-modal>
@@ -101,6 +132,8 @@ export default {
101
132
  composing: false,
102
133
  sending: false,
103
134
  sendSucceeded: false,
135
+ sendRejected: false,
136
+ helpDeskUrl: 'https://asd20.org/help-desk',
104
137
  emailMessage: {
105
138
  senderName: '',
106
139
  senderEmail: '',
@@ -108,6 +141,9 @@ export default {
108
141
  },
109
142
  }),
110
143
  computed: {
144
+ modalTitle() {
145
+ return this.sendRejected ? 'Contact our Help Desk' : 'Send an Email'
146
+ },
111
147
  isValid() {
112
148
  return (
113
149
  this.validationErrors.senderName.length === 0 &&
@@ -172,6 +208,7 @@ export default {
172
208
  resetSendState() {
173
209
  this.sending = false
174
210
  this.sendSucceeded = false
211
+ this.sendRejected = false
175
212
  },
176
213
  waitForSuccessMessage() {
177
214
  return new Promise(resolve => {
@@ -192,6 +229,24 @@ export default {
192
229
 
193
230
  return 'Something went wrong while sending your email. Please try again later.'
194
231
  },
232
+ getSendEmailResponseData(error) {
233
+ if (error?.response?.data) return error.response.data
234
+
235
+ const message = String(error?.message || '')
236
+ const jsonStart = message.indexOf('{')
237
+ if (jsonStart < 0) return null
238
+
239
+ try {
240
+ return JSON.parse(message.slice(jsonStart))
241
+ } catch (_error) {
242
+ return null
243
+ }
244
+ },
245
+ isHelpDeskRejection(error) {
246
+ return (
247
+ this.getSendEmailResponseData(error)?.code === 'moderation_rejected'
248
+ )
249
+ },
195
250
  async sendEmail(captchaToken = '') {
196
251
  if (!this.isValid) return
197
252
 
@@ -224,6 +279,13 @@ export default {
224
279
  } catch (error) {
225
280
  this.sendSucceeded = false
226
281
  console.error('Email send failed:', error?.message || error)
282
+ if (this.isHelpDeskRejection(error)) {
283
+ this.helpDeskUrl =
284
+ this.getSendEmailResponseData(error)?.helpDeskUrl ||
285
+ 'https://asd20.org/help-desk'
286
+ this.sendRejected = true
287
+ return
288
+ }
227
289
  alert(this.getSendEmailFailureMessage(error))
228
290
  } finally {
229
291
  this.sending = false
@@ -253,6 +315,22 @@ export default {
253
315
  margin: 0;
254
316
  text-align: center;
255
317
  }
318
+
319
+ &__rejection {
320
+ display: flex;
321
+ flex-direction: column;
322
+ gap: space(1);
323
+ }
324
+
325
+ &__rejection-message {
326
+ margin: 0;
327
+ }
328
+
329
+ &__rejection-actions {
330
+ display: flex;
331
+ flex-wrap: wrap;
332
+ gap: space(0.75);
333
+ }
256
334
  }
257
335
 
258
336
  @media (min-width: 1024px) {