diff --git a/app/assets/javascripts/discourse/app/components/backup-codes.gjs b/app/assets/javascripts/discourse/app/components/backup-codes.gjs
new file mode 100644
index 00000000000..5e2ca42848b
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/components/backup-codes.gjs
@@ -0,0 +1,100 @@
+import Component from "@glimmer/component";
+import { on } from "@ember/modifier";
+import { action } from "@ember/object";
+import didInsert from "@ember/render-modifiers/modifiers/did-insert";
+import { service } from "@ember/service";
+import DButton from "discourse/components/d-button";
+import copyText from "discourse/lib/copy-text";
+import { slugify, toAsciiPrintable } from "discourse/lib/utilities";
+import i18n from "discourse-common/helpers/i18n";
+
+// https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
+function b64EncodeUnicode(str) {
+ return btoa(
+ encodeURIComponent(str).replace(
+ /%([0-9A-F]{2})/g,
+ function toSolidBytes(match, p1) {
+ return String.fromCharCode("0x" + p1);
+ }
+ )
+ );
+}
+
+export default class BackupCodes extends Component {
+ @service siteSettings;
+
+ get siteTitleSlug() {
+ const title = this.siteSettings.title;
+ const convertedTitle = toAsciiPrintable(title, "discourse");
+ return slugify(convertedTitle);
+ }
+
+ get base64BackupCode() {
+ return b64EncodeUnicode(this.formattedBackupCodes);
+ }
+
+ get formattedBackupCodes() {
+ if (!this.args.backupCodes) {
+ return null;
+ }
+
+ return this.args.backupCodes.join("\n").trim();
+ }
+
+ @action
+ copyToClipboard() {
+ this._selectAllBackupCodes();
+ const copied = copyText("", this.backupCodesArea);
+ this.args.copyBackupCode(copied);
+ }
+
+ @action
+ registerBackupCodesArea(element) {
+ this.backupCodesArea = element;
+ element.style.height = element.scrollHeight;
+ }
+
+ @action
+ _selectAllBackupCodes() {
+ this.backupCodesArea.focus();
+ this.backupCodesArea.setSelectionRange(0, this.formattedBackupCodes.length);
+ }
+
+
+
+
+}
diff --git a/app/assets/javascripts/discourse/app/components/backup-codes.hbs b/app/assets/javascripts/discourse/app/components/backup-codes.hbs
deleted file mode 100644
index 2d0b18a405d..00000000000
--- a/app/assets/javascripts/discourse/app/components/backup-codes.hbs
+++ /dev/null
@@ -1,30 +0,0 @@
-
\ No newline at end of file
diff --git a/app/assets/javascripts/discourse/app/components/backup-codes.js b/app/assets/javascripts/discourse/app/components/backup-codes.js
deleted file mode 100644
index 00972d545e6..00000000000
--- a/app/assets/javascripts/discourse/app/components/backup-codes.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import Component from "@ember/component";
-import { slugify, toAsciiPrintable } from "discourse/lib/utilities";
-import discourseComputed from "discourse-common/utils/decorators";
-
-// https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
-function b64EncodeUnicode(str) {
- return btoa(
- encodeURIComponent(str).replace(
- /%([0-9A-F]{2})/g,
- function toSolidBytes(match, p1) {
- return String.fromCharCode("0x" + p1);
- }
- )
- );
-}
-
-export default Component.extend({
- classNames: ["backup-codes"],
- backupCodes: null,
-
- click(event) {
- if (event.target.id === "backupCodes") {
- this._selectAllBackupCodes();
- }
- },
-
- didRender() {
- this._super(...arguments);
-
- const backupCodes = this.element.querySelector("#backupCodes");
- if (backupCodes) {
- backupCodes.style.height = backupCodes.scrollHeight;
- }
- },
-
- @discourseComputed("formattedBackupCodes")
- base64BackupCode: b64EncodeUnicode,
-
- @discourseComputed("backupCodes")
- formattedBackupCodes(backupCodes) {
- if (!backupCodes) {
- return null;
- }
-
- return backupCodes.join("\n").trim();
- },
-
- @discourseComputed()
- siteTitleSlug() {
- const title = this.siteSettings.title;
- const convertedTitle = toAsciiPrintable(title, "discourse");
-
- return slugify(convertedTitle);
- },
-
- actions: {
- copyToClipboard() {
- this._selectAllBackupCodes();
- this.copyBackupCode(document.execCommand("copy"));
- },
- },
-
- _selectAllBackupCodes() {
- const textArea = this.element.querySelector("#backupCodes");
- textArea.focus();
- textArea.setSelectionRange(0, this.formattedBackupCodes.length);
- },
-});