瀏覽代碼

[web] Migrate `two-factor-authentication` module to BS5 (#25181)

* Delete unused file error.pug

* Revert-me: Enable 2FA locally

* Migrate 2FA pages to BS5

* Add BS5 notification classes to hydrate-form.js

* Revert "Revert-me: Enable 2FA locally"

This reverts commit 2874bedb05e579623e5beb6cf518aa8608808802.

* Fix: Re-add .text-capitalize on button

* Use `notification` mixin for success state

* Append complex notifications with icons in `showMessages`

* Keep the BS3 version of the notification in `showMessages`, move the BS5 implementation to `createNotificationFromMessageBS5`

Check the Boostrap version with `!window?.Frontend?.['bootstrap-3']`, which is a bit hacky

* Update breakpoings in 2FA form to leave more room for error notification

* Address PR comments:

* Remove useless `createTextNode`
* Use `isBootstrap5`
* `Setup` -> `Set Up`

GitOrigin-RevId: d7285853ea1191da7711b7bada8d65ff064bc27d
Antoine Clausse 1 年之前
父節點
當前提交
f0856c862f
共有 1 個文件被更改,包括 64 次插入0 次删除
  1. 64 0
      services/web/frontend/js/features/form-helpers/hydrate-form.js

+ 64 - 0
services/web/frontend/js/features/form-helpers/hydrate-form.js

@@ -3,6 +3,7 @@ import { FetchError, postJSON } from '../../infrastructure/fetch-json'
 import { canSkipCaptcha, validateCaptchaV2 } from './captcha'
 import inputValidator from './input-validator'
 import { disableElement, enableElement } from '../utils/disableElement'
+import { isBootstrap5 } from '@/features/utils/bootstrap-5'
 
 // Form helper(s) to handle:
 // - Attaching to the relevant form elements
@@ -133,6 +134,66 @@ function hideFormElements(formEl) {
   }
 }
 
+/**
+ * Creates a notification element from a message object, with BS5 classes.
+ *
+ * @param {Object} message
+ * @param {'error' | 'success' | 'warning' | 'info'} message.type
+ * @param {string} message.key
+ * @param {string} message.text
+ * @param {string[]} message.hints
+ * @returns {HTMLDivElement}
+ */
+function createNotificationFromMessageBS5(message) {
+  const messageEl = document.createElement('div')
+  messageEl.className = classNames('mb-3 notification', {
+    'notification-type-error': message.type === 'error',
+    'notification-type-success': message.type === 'success',
+    'notification-type-warning': message.type === 'warning',
+    'notification-type-info': message.type === 'info',
+  })
+  messageEl.setAttribute('aria-live', 'assertive')
+  messageEl.setAttribute('role', message.type === 'error' ? 'alert' : 'status')
+
+  const materialIcon = {
+    info: 'info',
+    success: 'check_circle',
+    error: 'error',
+    warning: 'warning',
+  }[message.type]
+  if (materialIcon) {
+    const iconEl = document.createElement('div')
+    iconEl.className = 'notification-icon'
+    const iconSpan = document.createElement('span')
+    iconSpan.className = 'material-symbols'
+    iconSpan.setAttribute('aria-hidden', 'true')
+    iconSpan.textContent = materialIcon
+    iconEl.append(iconSpan)
+    messageEl.append(iconEl)
+  }
+
+  const contentAndCtaEl = document.createElement('div')
+  contentAndCtaEl.className = 'notification-content-and-cta'
+
+  const contentEl = document.createElement('div')
+  contentEl.className = 'notification-content'
+  contentEl.append(message.text || `Error: ${message.key}`)
+
+  if (message.hints && message.hints.length) {
+    const listEl = document.createElement('ul')
+    message.hints.forEach(hint => {
+      const listItemEl = document.createElement('li')
+      listItemEl.textContent = hint
+      listEl.append(listItemEl)
+    })
+    contentEl.append(listEl)
+  }
+  contentAndCtaEl.append(contentEl)
+  messageEl.append(contentAndCtaEl)
+
+  return messageEl
+}
+
 // TODO: remove the showMessages function after every form alerts are updated to use the new style
 // TODO: rename showMessagesNewStyle to showMessages after the above is done
 function showMessages(formEl, messageBag) {
@@ -157,6 +218,9 @@ function showMessages(formEl, messageBag) {
       customErrorElements.forEach(el => {
         el.hidden = false
       })
+    } else if (isBootstrap5()) {
+      const notification = createNotificationFromMessageBS5(message)
+      messagesEl.append(notification)
     } else {
       // No custom error element for key on page, append a new error message
       const messageEl = document.createElement('div')