@vue-skuilder/common-ui 0.2.35 → 0.2.37

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.
Files changed (190) hide show
  1. package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/defineProperty.mjs +13 -0
  2. package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/toPrimitive.mjs +15 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/toPropertyKey.mjs +10 -0
  4. package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/typeof.mjs +12 -0
  5. package/dist/_virtual/_plugin-vue_export-helper.mjs +9 -0
  6. package/dist/_virtual/_rolldown/runtime.mjs +7 -0
  7. package/dist/admin/common-ui-admin.es.js +259 -23774
  8. package/dist/admin/common-ui-admin.es.js.map +1 -1
  9. package/dist/assets/index.css +2 -1
  10. package/dist/components/CardBrowser.mjs +63 -0
  11. package/dist/components/CardBrowser.mjs.map +1 -0
  12. package/dist/components/CardBrowser.vue_vue_type_script_lang.mjs +50 -0
  13. package/dist/components/CardBrowser.vue_vue_type_script_lang.mjs.map +1 -0
  14. package/dist/components/CardHistoryViewer.mjs +70 -0
  15. package/dist/components/CardHistoryViewer.mjs.map +1 -0
  16. package/dist/components/CardHistoryViewer.vue_vue_type_script_lang.mjs +108 -0
  17. package/dist/components/CardHistoryViewer.vue_vue_type_script_lang.mjs.map +1 -0
  18. package/dist/components/CardSearch.mjs +26 -0
  19. package/dist/components/CardSearch.mjs.map +1 -0
  20. package/dist/components/CardSearch.vue_vue_type_script_lang.mjs +17 -0
  21. package/dist/components/CardSearch.vue_vue_type_script_lang.mjs.map +1 -0
  22. package/dist/components/CardSearchResults.mjs +32 -0
  23. package/dist/components/CardSearchResults.mjs.map +1 -0
  24. package/dist/components/CardSearchResults.vue_vue_type_script_lang.mjs +71 -0
  25. package/dist/components/CardSearchResults.vue_vue_type_script_lang.mjs.map +1 -0
  26. package/dist/components/CourseCardBrowser.mjs +175 -0
  27. package/dist/components/CourseCardBrowser.mjs.map +1 -0
  28. package/dist/components/CourseCardBrowser.vue_vue_type_script_lang.mjs +173 -0
  29. package/dist/components/CourseCardBrowser.vue_vue_type_script_lang.mjs.map +1 -0
  30. package/dist/components/CourseInformation.mjs +132 -0
  31. package/dist/components/CourseInformation.mjs.map +1 -0
  32. package/dist/components/CourseInformation.vue_vue_type_script_lang.mjs +56 -0
  33. package/dist/components/CourseInformation.vue_vue_type_script_lang.mjs.map +1 -0
  34. package/dist/components/CourseTagFilterWidget.mjs +114 -0
  35. package/dist/components/CourseTagFilterWidget.mjs.map +1 -0
  36. package/dist/components/CourseTagFilterWidget.vue_vue_type_script_lang.mjs +65 -0
  37. package/dist/components/CourseTagFilterWidget.vue_vue_type_script_lang.mjs.map +1 -0
  38. package/dist/components/HeatMap.mjs +40 -0
  39. package/dist/components/HeatMap.mjs.map +1 -0
  40. package/dist/components/HeatMap.vue_vue_type_script_lang.mjs +211 -0
  41. package/dist/components/HeatMap.vue_vue_type_script_lang.mjs.map +1 -0
  42. package/dist/components/PaginatingToolbar.mjs +94 -0
  43. package/dist/components/PaginatingToolbar.mjs.map +1 -0
  44. package/dist/components/PaginatingToolbar.vue_vue_type_script_lang.mjs +36 -0
  45. package/dist/components/PaginatingToolbar.vue_vue_type_script_lang.mjs.map +1 -0
  46. package/dist/components/SessionControllerDebug.mjs +130 -0
  47. package/dist/components/SessionControllerDebug.mjs.map +1 -0
  48. package/dist/components/SessionControllerDebug.vue_vue_type_script_lang.mjs +45 -0
  49. package/dist/components/SessionControllerDebug.vue_vue_type_script_lang.mjs.map +1 -0
  50. package/dist/components/SkMouseTrap.mjs +66 -0
  51. package/dist/components/SkMouseTrap.mjs.map +1 -0
  52. package/dist/components/SkMouseTrap.vue_vue_type_script_lang.mjs +31 -0
  53. package/dist/components/SkMouseTrap.vue_vue_type_script_lang.mjs.map +1 -0
  54. package/dist/components/SkMouseTrapToolTip.mjs +28 -0
  55. package/dist/components/SkMouseTrapToolTip.mjs.map +1 -0
  56. package/dist/components/SkMouseTrapToolTip.vue_vue_type_script_lang.mjs +91 -0
  57. package/dist/components/SkMouseTrapToolTip.vue_vue_type_script_lang.mjs.map +1 -0
  58. package/dist/components/SnackbarService.mjs +24 -0
  59. package/dist/components/SnackbarService.mjs.map +1 -0
  60. package/dist/components/SnackbarService.vue_vue_type_script_lang.mjs +34 -0
  61. package/dist/components/SnackbarService.vue_vue_type_script_lang.mjs.map +1 -0
  62. package/dist/components/SnackbarService2.mjs +40 -0
  63. package/dist/components/SnackbarService2.mjs.map +1 -0
  64. package/dist/components/StudySession.mjs +123 -0
  65. package/dist/components/StudySession.mjs.map +1 -0
  66. package/dist/components/StudySession.vue_vue_type_script_lang.mjs +280 -0
  67. package/dist/components/StudySession.vue_vue_type_script_lang.mjs.map +1 -0
  68. package/dist/components/StudySessionTimer.mjs +50 -0
  69. package/dist/components/StudySessionTimer.mjs.map +1 -0
  70. package/dist/components/StudySessionTimer.vue_vue_type_script_lang.mjs +43 -0
  71. package/dist/components/StudySessionTimer.vue_vue_type_script_lang.mjs.map +1 -0
  72. package/dist/components/TagsInput.mjs +45 -0
  73. package/dist/components/TagsInput.mjs.map +1 -0
  74. package/dist/components/TagsInput.vue_vue_type_script_lang.mjs +117 -0
  75. package/dist/components/TagsInput.vue_vue_type_script_lang.mjs.map +1 -0
  76. package/dist/components/UserTagPreferences.mjs +205 -0
  77. package/dist/components/UserTagPreferences.mjs.map +1 -0
  78. package/dist/components/UserTagPreferences.vue_vue_type_script_lang.mjs +139 -0
  79. package/dist/components/UserTagPreferences.vue_vue_type_script_lang.mjs.map +1 -0
  80. package/dist/components/auth/RequestPasswordReset.mjs +96 -0
  81. package/dist/components/auth/RequestPasswordReset.mjs.map +1 -0
  82. package/dist/components/auth/RequestPasswordReset.vue_vue_type_script_lang.mjs +47 -0
  83. package/dist/components/auth/RequestPasswordReset.vue_vue_type_script_lang.mjs.map +1 -0
  84. package/dist/components/auth/ResetPassword.mjs +129 -0
  85. package/dist/components/auth/ResetPassword.mjs.map +1 -0
  86. package/dist/components/auth/ResetPassword.vue_vue_type_script_lang.mjs +69 -0
  87. package/dist/components/auth/ResetPassword.vue_vue_type_script_lang.mjs.map +1 -0
  88. package/dist/components/auth/UserChip.mjs +9 -0
  89. package/dist/components/auth/UserChip.mjs.map +1 -0
  90. package/dist/components/auth/UserChip.vue_vue_type_script_setup_true_lang.mjs +213 -0
  91. package/dist/components/auth/UserChip.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  92. package/dist/components/auth/UserLogin.mjs +9 -0
  93. package/dist/components/auth/UserLogin.mjs.map +1 -0
  94. package/dist/components/auth/UserLogin.vue_vue_type_script_setup_true_lang.mjs +155 -0
  95. package/dist/components/auth/UserLogin.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  96. package/dist/components/auth/UserLoginAndRegistrationContainer.mjs +9 -0
  97. package/dist/components/auth/UserLoginAndRegistrationContainer.mjs.map +1 -0
  98. package/dist/components/auth/UserLoginAndRegistrationContainer.vue_vue_type_script_setup_true_lang.mjs +126 -0
  99. package/dist/components/auth/UserLoginAndRegistrationContainer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  100. package/dist/components/auth/UserRegistration.mjs +147 -0
  101. package/dist/components/auth/UserRegistration.mjs.map +1 -0
  102. package/dist/components/auth/UserRegistration.vue_vue_type_script_lang.mjs +130 -0
  103. package/dist/components/auth/UserRegistration.vue_vue_type_script_lang.mjs.map +1 -0
  104. package/dist/components/auth/VerifyEmail.mjs +118 -0
  105. package/dist/components/auth/VerifyEmail.mjs.map +1 -0
  106. package/dist/components/auth/VerifyEmail.vue_vue_type_script_lang.mjs +59 -0
  107. package/dist/components/auth/VerifyEmail.vue_vue_type_script_lang.mjs.map +1 -0
  108. package/dist/components/cardRendering/AudioAutoPlayer.mjs +9 -0
  109. package/dist/components/cardRendering/AudioAutoPlayer.mjs.map +1 -0
  110. package/dist/components/cardRendering/AudioAutoPlayer.vue_vue_type_script_setup_true_lang.mjs +69 -0
  111. package/dist/components/cardRendering/AudioAutoPlayer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  112. package/dist/components/cardRendering/CardLoader.mjs +31 -0
  113. package/dist/components/cardRendering/CardLoader.mjs.map +1 -0
  114. package/dist/components/cardRendering/CardLoader.vue_vue_type_script_lang.mjs +75 -0
  115. package/dist/components/cardRendering/CardLoader.vue_vue_type_script_lang.mjs.map +1 -0
  116. package/dist/components/cardRendering/CardViewer.mjs +39 -0
  117. package/dist/components/cardRendering/CardViewer.mjs.map +1 -0
  118. package/dist/components/cardRendering/CardViewer.vue_vue_type_script_lang.mjs +66 -0
  119. package/dist/components/cardRendering/CardViewer.vue_vue_type_script_lang.mjs.map +1 -0
  120. package/dist/components/cardRendering/CodeBlockRenderer.mjs +8 -0
  121. package/dist/components/cardRendering/CodeBlockRenderer.mjs.map +1 -0
  122. package/dist/components/cardRendering/CodeBlockRenderer.vue_vue_type_script_setup_true_lang.mjs +44 -0
  123. package/dist/components/cardRendering/CodeBlockRenderer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  124. package/dist/components/cardRendering/MarkdownRenderer.mjs +21 -0
  125. package/dist/components/cardRendering/MarkdownRenderer.mjs.map +1 -0
  126. package/dist/components/cardRendering/MarkdownRenderer.vue_vue_type_script_lang.mjs +24 -0
  127. package/dist/components/cardRendering/MarkdownRenderer.vue_vue_type_script_lang.mjs.map +1 -0
  128. package/dist/components/cardRendering/MarkdownRendererHelpers.mjs +79 -0
  129. package/dist/components/cardRendering/MarkdownRendererHelpers.mjs.map +1 -0
  130. package/dist/components/cardRendering/MdTokenRenderer.mjs +9 -0
  131. package/dist/components/cardRendering/MdTokenRenderer.mjs.map +1 -0
  132. package/dist/components/cardRendering/MdTokenRenderer.vue_vue_type_script_setup_true_lang.mjs +176 -0
  133. package/dist/components/cardRendering/MdTokenRenderer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  134. package/dist/components/studentInputs/BaseUserInput.mjs +54 -0
  135. package/dist/components/studentInputs/BaseUserInput.mjs.map +1 -0
  136. package/dist/components/studentInputs/MultipleChoiceOption.mjs +26 -0
  137. package/dist/components/studentInputs/MultipleChoiceOption.mjs.map +1 -0
  138. package/dist/components/studentInputs/MultipleChoiceOption.vue_vue_type_script_lang.mjs +76 -0
  139. package/dist/components/studentInputs/MultipleChoiceOption.vue_vue_type_script_lang.mjs.map +1 -0
  140. package/dist/components/studentInputs/RadioMultipleChoice.mjs +33 -0
  141. package/dist/components/studentInputs/RadioMultipleChoice.mjs.map +1 -0
  142. package/dist/components/studentInputs/RadioMultipleChoice.vue_vue_type_script_lang.mjs +105 -0
  143. package/dist/components/studentInputs/RadioMultipleChoice.vue_vue_type_script_lang.mjs.map +1 -0
  144. package/dist/components/studentInputs/TrueFalse.mjs +19 -0
  145. package/dist/components/studentInputs/TrueFalse.mjs.map +1 -0
  146. package/dist/components/studentInputs/TrueFalse.vue_vue_type_script_lang.mjs +21 -0
  147. package/dist/components/studentInputs/TrueFalse.vue_vue_type_script_lang.mjs.map +1 -0
  148. package/dist/components/studentInputs/UserInputNumber.mjs +33 -0
  149. package/dist/components/studentInputs/UserInputNumber.mjs.map +1 -0
  150. package/dist/components/studentInputs/UserInputNumber.vue_vue_type_script_lang.mjs +25 -0
  151. package/dist/components/studentInputs/UserInputNumber.vue_vue_type_script_lang.mjs.map +1 -0
  152. package/dist/components/studentInputs/UserInputString.mjs +22 -0
  153. package/dist/components/studentInputs/UserInputString.mjs.map +1 -0
  154. package/dist/components/studentInputs/UserInputString.vue_vue_type_script_lang.mjs +23 -0
  155. package/dist/components/studentInputs/UserInputString.vue_vue_type_script_lang.mjs.map +1 -0
  156. package/dist/components/studentInputs/fillInInput.mjs +25 -0
  157. package/dist/components/studentInputs/fillInInput.mjs.map +1 -0
  158. package/dist/components/studentInputs/fillInInput.vue_vue_type_script_lang.mjs +26 -0
  159. package/dist/components/studentInputs/fillInInput.vue_vue_type_script_lang.mjs.map +1 -0
  160. package/dist/composables/CompositionViewable.mjs +65 -0
  161. package/dist/composables/CompositionViewable.mjs.map +1 -0
  162. package/dist/composables/Displayable.mjs +36 -0
  163. package/dist/composables/Displayable.mjs.map +1 -0
  164. package/dist/composables/useAuthUI.mjs +38 -0
  165. package/dist/composables/useAuthUI.mjs.map +1 -0
  166. package/dist/composables/useEntitlements.mjs +58 -0
  167. package/dist/composables/useEntitlements.mjs.map +1 -0
  168. package/dist/index.mjs +49 -0
  169. package/dist/plugins/pinia.mjs +12 -0
  170. package/dist/plugins/pinia.mjs.map +1 -0
  171. package/dist/services/authAPI.mjs +159 -0
  172. package/dist/services/authAPI.mjs.map +1 -0
  173. package/dist/stores/useAuthStore.mjs +68 -0
  174. package/dist/stores/useAuthStore.mjs.map +1 -0
  175. package/dist/stores/useCardPreviewModeStore.mjs +20 -0
  176. package/dist/stores/useCardPreviewModeStore.mjs.map +1 -0
  177. package/dist/stores/useConfigStore.mjs +60 -0
  178. package/dist/stores/useConfigStore.mjs.map +1 -0
  179. package/dist/utils/SkldrMouseTrap.mjs +48 -0
  180. package/dist/utils/SkldrMouseTrap.mjs.map +1 -0
  181. package/dist/utils/passwordValidation.mjs +12 -0
  182. package/dist/utils/passwordValidation.mjs.map +1 -0
  183. package/package.json +7 -8
  184. package/dist/MarkdownRenderer-U_iPiA2x.mjs +0 -4966
  185. package/dist/MarkdownRenderer-U_iPiA2x.mjs.map +0 -1
  186. package/dist/assets/MarkdownRenderer.css +0 -1
  187. package/dist/common-ui.es.js +0 -5090
  188. package/dist/common-ui.es.js.map +0 -1
  189. package/dist/common-ui.umd.js +0 -77
  190. package/dist/common-ui.umd.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResetPassword.vue_vue_type_script_lang.mjs","names":[],"sources":["../../../src/components/auth/ResetPassword.vue"],"sourcesContent":["<template>\n <v-container class=\"fill-height\" fluid>\n <v-row align=\"center\" justify=\"center\">\n <v-col cols=\"12\" sm=\"8\" md=\"6\">\n <v-card>\n <v-card-title class=\"text-h5 bg-grey-lighten-2\">\n Set New Password\n </v-card-title>\n\n <v-card-text class=\"pa-6\">\n <v-form v-if=\"!isComplete\" @submit.prevent=\"handleSubmit\">\n <p class=\"mb-4\">Enter your new password below.</p>\n\n <v-text-field\n v-model=\"password\"\n prepend-icon=\"mdi-lock\"\n name=\"password\"\n label=\"New password\"\n min=\"4\"\n :append-icon=\"passwordVisible ? 'mdi-eye-off' : 'mdi-eye'\"\n :type=\"passwordVisible ? 'text' : 'password'\"\n :disabled=\"isSubmitting\"\n @click:append=\"() => (passwordVisible = !passwordVisible)\"\n ></v-text-field>\n\n <v-text-field\n v-model=\"confirmPassword\"\n prepend-icon=\"mdi-lock\"\n name=\"confirmPassword\"\n label=\"Confirm new password\"\n min=\"4\"\n :type=\"passwordVisible ? 'text' : 'password'\"\n :error=\"confirmPasswordError\"\n :hint=\"confirmPasswordHint\"\n :disabled=\"isSubmitting\"\n @blur=\"validateConfirmPassword\"\n ></v-text-field>\n\n <v-btn\n type=\"submit\"\n color=\"primary\"\n class=\"mt-4\"\n :loading=\"isSubmitting\"\n :disabled=\"!canSubmit\"\n block\n >\n <v-icon start>mdi-lock-reset</v-icon>\n Reset Password\n </v-btn>\n </v-form>\n\n <!-- Success state -->\n <div v-else class=\"text-center\">\n <v-icon color=\"success\" size=\"64\" class=\"mb-4\">mdi-check-circle</v-icon>\n <h3 class=\"mb-2\">Password Reset Successful!</h3>\n <p>Your password has been updated. You can now log in with your new password.</p>\n </div>\n </v-card-text>\n\n <v-card-actions v-if=\"isComplete\">\n <v-spacer></v-spacer>\n <slot name=\"success-action\">\n <!-- External apps can provide their own navigation -->\n <v-btn color=\"primary\" @click=\"$emit('complete')\">\n Continue to Login\n </v-btn>\n </slot>\n </v-card-actions>\n </v-card>\n </v-col>\n </v-row>\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { resetPassword } from '../../services/authAPI';\nimport { alertUser } from '../SnackbarService';\nimport { Status } from '@vue-skuilder/common';\n\nexport default defineComponent({\n name: 'ResetPassword',\n\n emits: ['complete', 'error'],\n\n props: {\n /**\n * Reset token. If not provided, will try to read from URL query params.\n */\n token: {\n type: String,\n default: null,\n },\n },\n\n data() {\n return {\n password: '',\n confirmPassword: '',\n passwordVisible: false,\n confirmPasswordError: false,\n confirmPasswordHint: '',\n isSubmitting: false,\n isComplete: false,\n };\n },\n\n computed: {\n canSubmit(): boolean {\n return (\n this.password.length >= 4 &&\n this.confirmPassword.length >= 4 &&\n this.password === this.confirmPassword &&\n !this.confirmPasswordError\n );\n },\n },\n\n methods: {\n validateConfirmPassword() {\n this.confirmPasswordError = false;\n this.confirmPasswordHint = '';\n\n if (!this.confirmPassword) return;\n\n if (this.password !== this.confirmPassword) {\n this.confirmPasswordError = true;\n this.confirmPasswordHint = 'Passwords do not match';\n }\n },\n\n async handleSubmit() {\n this.validateConfirmPassword();\n\n if (!this.canSubmit) {\n return;\n }\n\n // Get token from prop or URL query params\n const token = this.token || this.getTokenFromURL();\n\n if (!token) {\n alertUser({\n text: 'No reset token provided. Please use the link from your email.',\n status: Status.error,\n });\n this.$emit('error', 'No token');\n return;\n }\n\n this.isSubmitting = true;\n\n try {\n const result = await resetPassword(token, this.password);\n\n if (result.ok) {\n this.isComplete = true;\n alertUser({\n text: 'Password reset successfully!',\n status: Status.ok,\n });\n } else {\n alertUser({\n text: result.error || 'Failed to reset password',\n status: Status.error,\n });\n this.$emit('error', result.error);\n }\n } catch (error) {\n alertUser({\n text: 'An unexpected error occurred',\n status: Status.error,\n });\n this.$emit('error', 'Unexpected error');\n } finally {\n this.isSubmitting = false;\n }\n },\n\n getTokenFromURL(): string | null {\n if (typeof window === 'undefined') return null;\n\n const params = new URLSearchParams(window.location.search);\n return params.get('token');\n },\n },\n});\n</script>\n"],"mappings":";;;;;;AAgFA,IAAA,IAAe,EAAgB;CAC7B,MAAM;CAEN,OAAO,CAAC,YAAY,QAAQ;CAE5B,OAAO,EAIL,OAAO;EACL,MAAM;EACN,SAAS;EACV,EACF;CAED,OAAO;AACL,SAAO;GACL,UAAU;GACV,iBAAiB;GACjB,iBAAiB;GACjB,sBAAsB;GACtB,qBAAqB;GACrB,cAAc;GACd,YAAY;GACb;;CAGH,UAAU,EACR,YAAqB;AACnB,SACE,KAAK,SAAS,UAAU,KACxB,KAAK,gBAAgB,UAAU,KAC/B,KAAK,aAAa,KAAK,mBACvB,CAAC,KAAK;IAGX;CAED,SAAS;EACP,0BAA0B;AACxB,QAAK,uBAAuB,IAC5B,KAAK,sBAAsB,IAEtB,KAAK,mBAEN,KAAK,aAAa,KAAK,oBACzB,KAAK,uBAAuB,IAC5B,KAAK,sBAAsB;;EAI/B,MAAM,eAAe;AAGnB,OAFA,KAAK,yBAAyB,EAE1B,CAAC,KAAK,UACR;GAIF,IAAM,IAAQ,KAAK,SAAS,KAAK,iBAAiB;AAElD,OAAI,CAAC,GAAO;AAKV,IAJA,EAAU;KACR,MAAM;KACN,QAAQ,EAAO;KAChB,CAAC,EACF,KAAK,MAAM,SAAS,WAAW;AAC/B;;AAGF,QAAK,eAAe;AAEpB,OAAI;IACF,IAAM,IAAS,MAAM,EAAc,GAAO,KAAK,SAAS;AAExD,IAAI,EAAO,MACT,KAAK,aAAa,IAClB,EAAU;KACR,MAAM;KACN,QAAQ,EAAO;KAChB,CAAC,KAEF,EAAU;KACR,MAAM,EAAO,SAAS;KACtB,QAAQ,EAAO;KAChB,CAAC,EACF,KAAK,MAAM,SAAS,EAAO,MAAM;WAErB;AAKd,IAJA,EAAU;KACR,MAAM;KACN,QAAQ,EAAO;KAChB,CAAC,EACF,KAAK,MAAM,SAAS,mBAAmB;aAC/B;AACR,SAAK,eAAe;;;EAIxB,kBAAiC;AAI/B,UAHI,OAAO,SAAW,MAAoB,OAE3B,IAAI,gBAAgB,OAAO,SAAS,OAAO,CAC5C,IAAI,QAAQ;;EAE7B;CACF,CAAC"}
@@ -0,0 +1,9 @@
1
+ import e from "../../_virtual/_plugin-vue_export-helper.mjs";
2
+ import t from "./UserChip.vue_vue_type_script_setup_true_lang.mjs";
3
+ /* empty css */
4
+ //#region src/components/auth/UserChip.vue
5
+ var n = /* @__PURE__ */ e(t, [["__scopeId", "data-v-9a38a213"]]);
6
+ //#endregion
7
+ export { n as default };
8
+
9
+ //# sourceMappingURL=UserChip.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserChip.mjs","names":[],"sources":["../../../src/components/auth/UserChip.vue"],"sourcesContent":["<template>\n <v-badge :content=\"items.length\" :model-value=\"hasNewItems\" color=\"accent\" location=\"end top\">\n <v-menu location=\"bottom end\" transition=\"scale-transition\">\n <template #activator=\"{ props }\">\n <v-chip v-bind=\"props\" class=\"ma-2\">\n <v-avatar start class=\"bg-primary\">\n <v-icon>mdi-school</v-icon>\n </v-avatar>\n {{ username }}\n </v-chip>\n </template>\n\n <v-list>\n <v-list-item v-for=\"item in items\" :key=\"item\" @click=\"dismiss(item)\">\n <v-list-item-title>{{ item }}</v-list-item-title>\n </v-list-item>\n\n <v-divider v-if=\"items.length\" />\n\n <v-list-item @click=\"gotoStats\">\n <template #prepend>\n <v-icon>mdi-trending-up</v-icon>\n </template>\n <v-list-item-title>Stats</v-list-item-title>\n </v-list-item>\n\n <v-list-item @click=\"gotoSettings\">\n <template #prepend>\n <v-icon>mdi-cog</v-icon>\n </template>\n <v-list-item-title>Settings</v-list-item-title>\n </v-list-item>\n\n <v-list-item v-if=\"authUIConfig.showLogout\" @click=\"logout\">\n <template #prepend>\n <v-icon>mdi-logout</v-icon>\n </template>\n <v-list-item-title>{{ authUIConfig.logoutLabel }}</v-list-item-title>\n </v-list-item>\n\n <v-list-item v-if=\"authUIConfig.showResetData\" @click=\"showResetDialog = true\">\n <template #prepend>\n <v-icon>mdi-delete-sweep</v-icon>\n </template>\n <v-list-item-title>{{ authUIConfig.resetLabel }}</v-list-item-title>\n </v-list-item>\n </v-list>\n </v-menu>\n </v-badge>\n\n <!-- Reset Confirmation Dialog -->\n <v-dialog v-model=\"showResetDialog\" max-width=\"500px\" persistent>\n <v-card>\n <v-card-title class=\"text-h5 d-flex align-center\">\n <v-icon color=\"warning\" class=\"mr-3\">mdi-alert-circle</v-icon>\n Reset All User Data\n </v-card-title>\n \n <v-card-text>\n <p class=\"mb-4\">This will permanently delete:</p>\n <ul class=\"mb-4\">\n <li>All course progress and history</li>\n <li>Scheduled card reviews</li>\n <li>Course registrations</li>\n <li>User preferences</li>\n </ul>\n <p class=\"mb-4 text-error font-weight-bold\">This cannot be undone.</p>\n \n <v-text-field\n v-model=\"confirmationText\"\n label='Type \"reset\" to confirm'\n outlined\n dense\n @keyup.enter=\"isConfirmationValid && executeReset()\"\n />\n </v-card-text>\n \n <v-card-actions>\n <v-spacer />\n <v-btn text @click=\"resetDialogState\">Cancel</v-btn>\n <v-btn \n color=\"error\" \n :disabled=\"!isConfirmationValid\"\n @click=\"executeReset\"\n >\n Reset All Data\n </v-btn>\n </v-card-actions>\n </v-card>\n </v-dialog>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ref, computed, onMounted } from 'vue';\nimport { useRouter } from 'vue-router';\nimport { getCurrentUser, useAuthStore } from '../../stores/useAuthStore';\nimport { useConfigStore } from '../../stores/useConfigStore';\nimport { useAuthUI } from '../../composables/useAuthUI';\n\n// Define props (even if not used, prevents warnings)\ndefineProps<{\n showLoginButton?: boolean;\n redirectToPath?: string;\n}>();\n\nconst router = useRouter();\nconst authStore = useAuthStore();\nconst configStore = useConfigStore();\nconst authUI = useAuthUI();\n\nconst username = ref('');\nconst items = ref<string[]>([]);\n\n// Reset confirmation dialog state\nconst showResetDialog = ref(false);\nconst confirmationText = ref('');\n\nconst isConfirmationValid = computed(() => confirmationText.value === 'reset');\n\nconst resetDialogState = () => {\n confirmationText.value = '';\n showResetDialog.value = false;\n};\n\nconst hasNewItems = computed(() => items.value.length > 0);\n\nconst authUIConfig = computed(() => {\n const configValue = authUI.config.value;\n const fallback = {\n showLoginRegistration: true,\n showLogout: true,\n showResetData: false,\n logoutLabel: 'Log out',\n resetLabel: '',\n };\n \n return configValue || fallback;\n});\n\nonMounted(async () => {\n const user = await getCurrentUser();\n username.value = user.getUsername();\n \n // Detect sync strategy for conditional UI\n await authUI.detectSyncStrategy();\n});\n\nconst gotoSettings = async () => {\n router.push(`/u/${(await getCurrentUser()).getUsername()}`);\n};\n\nconst gotoStats = async () => {\n router.push(`/u/${(await getCurrentUser()).getUsername()}/stats`);\n};\n\nconst dismiss = (item: string) => {\n const index = items.value.indexOf(item);\n items.value.splice(index, 1);\n};\n\nconst logout = async () => {\n const res = await authStore._user!.logout();\n if (res.ok) {\n authStore.loginAndRegistration = {\n init: true,\n loggedIn: false,\n regDialogOpen: false,\n loginDialogOpen: false,\n };\n\n configStore.resetDefaults();\n router.push('/home');\n }\n};\n\nconst executeReset = async () => {\n try {\n await authStore.resetUserData();\n configStore.resetDefaults();\n \n // Close dialog and navigate to home\n resetDialogState();\n router.push('/home');\n } catch (error) {\n console.error('Failed to reset user data:', error);\n // Could add a snackbar notification here\n }\n};\n</script>\n\n<style scoped>\n.component-fade-enter-active,\n.component-fade-leave-active {\n transition: opacity 0.5s ease;\n}\n.component-fade-enter,\n.component-fade-leave-to {\n opacity: 0;\n}\n</style>"],"mappings":""}
@@ -0,0 +1,213 @@
1
+ import "../../_virtual/_rolldown/runtime.mjs";
2
+ import { getCurrentUser as e, useAuthStore as t } from "../../stores/useAuthStore.mjs";
3
+ import { useConfigStore as n } from "../../stores/useConfigStore.mjs";
4
+ import { useAuthUI as r } from "../../composables/useAuthUI.mjs";
5
+ import { Fragment as i, computed as a, createBlock as o, createCommentVNode as s, createElementBlock as c, createElementVNode as l, createTextVNode as u, createVNode as d, defineComponent as f, mergeProps as p, onMounted as m, openBlock as h, ref as g, renderList as _, resolveComponent as v, toDisplayString as y, withCtx as b, withKeys as x } from "vue";
6
+ import { useRouter as S } from "vue-router";
7
+ //#region src/components/auth/UserChip.vue?vue&type=script&setup=true&lang.ts
8
+ var C = /* @__PURE__ */ f({
9
+ __name: "UserChip",
10
+ props: {
11
+ showLoginButton: { type: Boolean },
12
+ redirectToPath: {}
13
+ },
14
+ setup(f) {
15
+ let C = S(), w = t(), T = n(), E = r(), D = g(""), O = g([]), k = g(!1), A = g(""), j = a(() => A.value === "reset"), resetDialogState = () => {
16
+ A.value = "", k.value = !1;
17
+ }, M = a(() => O.value.length > 0), N = a(() => E.config.value || {
18
+ showLoginRegistration: !0,
19
+ showLogout: !0,
20
+ showResetData: !1,
21
+ logoutLabel: "Log out",
22
+ resetLabel: ""
23
+ });
24
+ m(async () => {
25
+ D.value = (await e()).getUsername(), await E.detectSyncStrategy();
26
+ });
27
+ let gotoSettings = async () => {
28
+ C.push(`/u/${(await e()).getUsername()}`);
29
+ }, gotoStats = async () => {
30
+ C.push(`/u/${(await e()).getUsername()}/stats`);
31
+ }, dismiss = (e) => {
32
+ let t = O.value.indexOf(e);
33
+ O.value.splice(t, 1);
34
+ }, logout = async () => {
35
+ (await w._user.logout()).ok && (w.loginAndRegistration = {
36
+ init: !0,
37
+ loggedIn: !1,
38
+ regDialogOpen: !1,
39
+ loginDialogOpen: !1
40
+ }, T.resetDefaults(), C.push("/home"));
41
+ }, executeReset = async () => {
42
+ try {
43
+ await w.resetUserData(), T.resetDefaults(), resetDialogState(), C.push("/home");
44
+ } catch (e) {
45
+ console.error("Failed to reset user data:", e);
46
+ }
47
+ };
48
+ return (e, t) => {
49
+ let n = v("v-icon"), r = v("v-avatar"), a = v("v-chip"), f = v("v-list-item-title"), m = v("v-list-item"), g = v("v-divider"), S = v("v-list"), C = v("v-menu"), w = v("v-badge"), T = v("v-card-title"), E = v("v-text-field"), P = v("v-card-text"), F = v("v-spacer"), I = v("v-btn"), L = v("v-card-actions"), R = v("v-card"), z = v("v-dialog");
50
+ return h(), c(i, null, [d(w, {
51
+ content: O.value.length,
52
+ "model-value": M.value,
53
+ color: "accent",
54
+ location: "end top"
55
+ }, {
56
+ default: b(() => [d(C, {
57
+ location: "bottom end",
58
+ transition: "scale-transition"
59
+ }, {
60
+ activator: b(({ props: e }) => [d(a, p(e, { class: "ma-2" }), {
61
+ default: b(() => [d(r, {
62
+ start: "",
63
+ class: "bg-primary"
64
+ }, {
65
+ default: b(() => [d(n, null, {
66
+ default: b(() => t[4] || (t[4] = [u("mdi-school")])),
67
+ _: 1
68
+ })]),
69
+ _: 1
70
+ }), u(" " + y(D.value), 1)]),
71
+ _: 2
72
+ }, 1040)]),
73
+ default: b(() => [d(S, null, {
74
+ default: b(() => [
75
+ (h(!0), c(i, null, _(O.value, (e) => (h(), o(m, {
76
+ key: e,
77
+ onClick: (t) => dismiss(e)
78
+ }, {
79
+ default: b(() => [d(f, null, {
80
+ default: b(() => [u(y(e), 1)]),
81
+ _: 2
82
+ }, 1024)]),
83
+ _: 2
84
+ }, 1032, ["onClick"]))), 128)),
85
+ O.value.length ? (h(), o(g, { key: 0 })) : s("", !0),
86
+ d(m, { onClick: gotoStats }, {
87
+ prepend: b(() => [d(n, null, {
88
+ default: b(() => t[5] || (t[5] = [u("mdi-trending-up")])),
89
+ _: 1
90
+ })]),
91
+ default: b(() => [d(f, null, {
92
+ default: b(() => t[6] || (t[6] = [u("Stats")])),
93
+ _: 1
94
+ })]),
95
+ _: 1
96
+ }),
97
+ d(m, { onClick: gotoSettings }, {
98
+ prepend: b(() => [d(n, null, {
99
+ default: b(() => t[7] || (t[7] = [u("mdi-cog")])),
100
+ _: 1
101
+ })]),
102
+ default: b(() => [d(f, null, {
103
+ default: b(() => t[8] || (t[8] = [u("Settings")])),
104
+ _: 1
105
+ })]),
106
+ _: 1
107
+ }),
108
+ N.value.showLogout ? (h(), o(m, {
109
+ key: 1,
110
+ onClick: logout
111
+ }, {
112
+ prepend: b(() => [d(n, null, {
113
+ default: b(() => t[9] || (t[9] = [u("mdi-logout")])),
114
+ _: 1
115
+ })]),
116
+ default: b(() => [d(f, null, {
117
+ default: b(() => [u(y(N.value.logoutLabel), 1)]),
118
+ _: 1
119
+ })]),
120
+ _: 1
121
+ })) : s("", !0),
122
+ N.value.showResetData ? (h(), o(m, {
123
+ key: 2,
124
+ onClick: t[0] || (t[0] = (e) => k.value = !0)
125
+ }, {
126
+ prepend: b(() => [d(n, null, {
127
+ default: b(() => t[10] || (t[10] = [u("mdi-delete-sweep")])),
128
+ _: 1
129
+ })]),
130
+ default: b(() => [d(f, null, {
131
+ default: b(() => [u(y(N.value.resetLabel), 1)]),
132
+ _: 1
133
+ })]),
134
+ _: 1
135
+ })) : s("", !0)
136
+ ]),
137
+ _: 1
138
+ })]),
139
+ _: 1
140
+ })]),
141
+ _: 1
142
+ }, 8, ["content", "model-value"]), d(z, {
143
+ modelValue: k.value,
144
+ "onUpdate:modelValue": t[3] || (t[3] = (e) => k.value = e),
145
+ "max-width": "500px",
146
+ persistent: ""
147
+ }, {
148
+ default: b(() => [d(R, null, {
149
+ default: b(() => [
150
+ d(T, { class: "text-h5 d-flex align-center" }, {
151
+ default: b(() => [d(n, {
152
+ color: "warning",
153
+ class: "mr-3"
154
+ }, {
155
+ default: b(() => t[11] || (t[11] = [u("mdi-alert-circle")])),
156
+ _: 1
157
+ }), t[12] || (t[12] = u(" Reset All User Data "))]),
158
+ _: 1
159
+ }),
160
+ d(P, null, {
161
+ default: b(() => [
162
+ t[13] || (t[13] = l("p", { class: "mb-4" }, "This will permanently delete:", -1)),
163
+ t[14] || (t[14] = l("ul", { class: "mb-4" }, [
164
+ l("li", null, "All course progress and history"),
165
+ l("li", null, "Scheduled card reviews"),
166
+ l("li", null, "Course registrations"),
167
+ l("li", null, "User preferences")
168
+ ], -1)),
169
+ t[15] || (t[15] = l("p", { class: "mb-4 text-error font-weight-bold" }, "This cannot be undone.", -1)),
170
+ d(E, {
171
+ modelValue: A.value,
172
+ "onUpdate:modelValue": t[1] || (t[1] = (e) => A.value = e),
173
+ label: "Type \"reset\" to confirm",
174
+ outlined: "",
175
+ dense: "",
176
+ onKeyup: t[2] || (t[2] = x((e) => j.value && executeReset(), ["enter"]))
177
+ }, null, 8, ["modelValue"])
178
+ ]),
179
+ _: 1
180
+ }),
181
+ d(L, null, {
182
+ default: b(() => [
183
+ d(F),
184
+ d(I, {
185
+ text: "",
186
+ onClick: resetDialogState
187
+ }, {
188
+ default: b(() => t[16] || (t[16] = [u("Cancel")])),
189
+ _: 1
190
+ }),
191
+ d(I, {
192
+ color: "error",
193
+ disabled: !j.value,
194
+ onClick: executeReset
195
+ }, {
196
+ default: b(() => t[17] || (t[17] = [u(" Reset All Data ")])),
197
+ _: 1
198
+ }, 8, ["disabled"])
199
+ ]),
200
+ _: 1
201
+ })
202
+ ]),
203
+ _: 1
204
+ })]),
205
+ _: 1
206
+ }, 8, ["modelValue"])], 64);
207
+ };
208
+ }
209
+ });
210
+ //#endregion
211
+ export { C as default };
212
+
213
+ //# sourceMappingURL=UserChip.vue_vue_type_script_setup_true_lang.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserChip.vue_vue_type_script_setup_true_lang.mjs","names":[],"sources":["../../../src/components/auth/UserChip.vue"],"sourcesContent":["<template>\n <v-badge :content=\"items.length\" :model-value=\"hasNewItems\" color=\"accent\" location=\"end top\">\n <v-menu location=\"bottom end\" transition=\"scale-transition\">\n <template #activator=\"{ props }\">\n <v-chip v-bind=\"props\" class=\"ma-2\">\n <v-avatar start class=\"bg-primary\">\n <v-icon>mdi-school</v-icon>\n </v-avatar>\n {{ username }}\n </v-chip>\n </template>\n\n <v-list>\n <v-list-item v-for=\"item in items\" :key=\"item\" @click=\"dismiss(item)\">\n <v-list-item-title>{{ item }}</v-list-item-title>\n </v-list-item>\n\n <v-divider v-if=\"items.length\" />\n\n <v-list-item @click=\"gotoStats\">\n <template #prepend>\n <v-icon>mdi-trending-up</v-icon>\n </template>\n <v-list-item-title>Stats</v-list-item-title>\n </v-list-item>\n\n <v-list-item @click=\"gotoSettings\">\n <template #prepend>\n <v-icon>mdi-cog</v-icon>\n </template>\n <v-list-item-title>Settings</v-list-item-title>\n </v-list-item>\n\n <v-list-item v-if=\"authUIConfig.showLogout\" @click=\"logout\">\n <template #prepend>\n <v-icon>mdi-logout</v-icon>\n </template>\n <v-list-item-title>{{ authUIConfig.logoutLabel }}</v-list-item-title>\n </v-list-item>\n\n <v-list-item v-if=\"authUIConfig.showResetData\" @click=\"showResetDialog = true\">\n <template #prepend>\n <v-icon>mdi-delete-sweep</v-icon>\n </template>\n <v-list-item-title>{{ authUIConfig.resetLabel }}</v-list-item-title>\n </v-list-item>\n </v-list>\n </v-menu>\n </v-badge>\n\n <!-- Reset Confirmation Dialog -->\n <v-dialog v-model=\"showResetDialog\" max-width=\"500px\" persistent>\n <v-card>\n <v-card-title class=\"text-h5 d-flex align-center\">\n <v-icon color=\"warning\" class=\"mr-3\">mdi-alert-circle</v-icon>\n Reset All User Data\n </v-card-title>\n \n <v-card-text>\n <p class=\"mb-4\">This will permanently delete:</p>\n <ul class=\"mb-4\">\n <li>All course progress and history</li>\n <li>Scheduled card reviews</li>\n <li>Course registrations</li>\n <li>User preferences</li>\n </ul>\n <p class=\"mb-4 text-error font-weight-bold\">This cannot be undone.</p>\n \n <v-text-field\n v-model=\"confirmationText\"\n label='Type \"reset\" to confirm'\n outlined\n dense\n @keyup.enter=\"isConfirmationValid && executeReset()\"\n />\n </v-card-text>\n \n <v-card-actions>\n <v-spacer />\n <v-btn text @click=\"resetDialogState\">Cancel</v-btn>\n <v-btn \n color=\"error\" \n :disabled=\"!isConfirmationValid\"\n @click=\"executeReset\"\n >\n Reset All Data\n </v-btn>\n </v-card-actions>\n </v-card>\n </v-dialog>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ref, computed, onMounted } from 'vue';\nimport { useRouter } from 'vue-router';\nimport { getCurrentUser, useAuthStore } from '../../stores/useAuthStore';\nimport { useConfigStore } from '../../stores/useConfigStore';\nimport { useAuthUI } from '../../composables/useAuthUI';\n\n// Define props (even if not used, prevents warnings)\ndefineProps<{\n showLoginButton?: boolean;\n redirectToPath?: string;\n}>();\n\nconst router = useRouter();\nconst authStore = useAuthStore();\nconst configStore = useConfigStore();\nconst authUI = useAuthUI();\n\nconst username = ref('');\nconst items = ref<string[]>([]);\n\n// Reset confirmation dialog state\nconst showResetDialog = ref(false);\nconst confirmationText = ref('');\n\nconst isConfirmationValid = computed(() => confirmationText.value === 'reset');\n\nconst resetDialogState = () => {\n confirmationText.value = '';\n showResetDialog.value = false;\n};\n\nconst hasNewItems = computed(() => items.value.length > 0);\n\nconst authUIConfig = computed(() => {\n const configValue = authUI.config.value;\n const fallback = {\n showLoginRegistration: true,\n showLogout: true,\n showResetData: false,\n logoutLabel: 'Log out',\n resetLabel: '',\n };\n \n return configValue || fallback;\n});\n\nonMounted(async () => {\n const user = await getCurrentUser();\n username.value = user.getUsername();\n \n // Detect sync strategy for conditional UI\n await authUI.detectSyncStrategy();\n});\n\nconst gotoSettings = async () => {\n router.push(`/u/${(await getCurrentUser()).getUsername()}`);\n};\n\nconst gotoStats = async () => {\n router.push(`/u/${(await getCurrentUser()).getUsername()}/stats`);\n};\n\nconst dismiss = (item: string) => {\n const index = items.value.indexOf(item);\n items.value.splice(index, 1);\n};\n\nconst logout = async () => {\n const res = await authStore._user!.logout();\n if (res.ok) {\n authStore.loginAndRegistration = {\n init: true,\n loggedIn: false,\n regDialogOpen: false,\n loginDialogOpen: false,\n };\n\n configStore.resetDefaults();\n router.push('/home');\n }\n};\n\nconst executeReset = async () => {\n try {\n await authStore.resetUserData();\n configStore.resetDefaults();\n \n // Close dialog and navigate to home\n resetDialogState();\n router.push('/home');\n } catch (error) {\n console.error('Failed to reset user data:', error);\n // Could add a snackbar notification here\n }\n};\n</script>\n\n<style scoped>\n.component-fade-enter-active,\n.component-fade-leave-active {\n transition: opacity 0.5s ease;\n}\n.component-fade-enter,\n.component-fade-leave-to {\n opacity: 0;\n}\n</style>"],"mappings":";;;;;;;;;;;;;;EAyGA,IAAM,IAAS,GAAW,EACpB,IAAY,GAAc,EAC1B,IAAc,GAAgB,EAC9B,IAAS,GAAW,EAEpB,IAAW,EAAI,GAAG,EAClB,IAAQ,EAAc,EAAE,CAAC,EAGzB,IAAkB,EAAI,GAAM,EAC5B,IAAmB,EAAI,GAAG,EAE1B,IAAsB,QAAe,EAAiB,UAAU,QAAQ,EAExE,yBAAyB;AAE7B,GADA,EAAiB,QAAQ,IACzB,EAAgB,QAAQ;KAGpB,IAAc,QAAe,EAAM,MAAM,SAAS,EAAE,EAEpD,IAAe,QACC,EAAO,OAAO,SACjB;GACf,uBAAuB;GACvB,YAAY;GACZ,eAAe;GACf,aAAa;GACb,YAAY;GACb,CAGD;AAEF,IAAU,YAAY;AAKpB,GAHA,EAAS,SADI,MAAM,GAAgB,EACb,aAAa,EAGnC,MAAM,EAAO,oBAAoB;IACjC;EAEF,IAAM,eAAe,YAAY;AAC/B,KAAO,KAAK,OAAO,MAAM,GAAgB,EAAE,aAAa,GAAG;KAGvD,YAAY,YAAY;AAC5B,KAAO,KAAK,OAAO,MAAM,GAAgB,EAAE,aAAa,CAAC,QAAQ;KAG7D,WAAW,MAAiB;GAChC,IAAM,IAAQ,EAAM,MAAM,QAAQ,EAAK;AACvC,KAAM,MAAM,OAAO,GAAO,EAAE;KAGxB,SAAS,YAAY;AAEzB,IADY,MAAM,EAAU,MAAO,QAAQ,EACnC,OACN,EAAU,uBAAuB;IAC/B,MAAM;IACN,UAAU;IACV,eAAe;IACf,iBAAiB;IAClB,EAED,EAAY,eAAe,EAC3B,EAAO,KAAK,QAAQ;KAIlB,eAAe,YAAY;AAC/B,OAAI;AAMF,IALA,MAAM,EAAU,eAAe,EAC/B,EAAY,eAAe,EAG3B,kBAAkB,EAClB,EAAO,KAAK,QAAQ;YACb,GAAO;AACd,YAAQ,MAAM,8BAA8B,EAAM"}
@@ -0,0 +1,9 @@
1
+ import e from "../../_virtual/_plugin-vue_export-helper.mjs";
2
+ import t from "./UserLogin.vue_vue_type_script_setup_true_lang.mjs";
3
+ /* empty css */
4
+ //#region src/components/auth/UserLogin.vue
5
+ var n = /* @__PURE__ */ e(t, [["__scopeId", "data-v-764d1a76"]]);
6
+ //#endregion
7
+ export { n as default };
8
+
9
+ //# sourceMappingURL=UserLogin.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserLogin.mjs","names":[],"sources":["../../../src/components/auth/UserLogin.vue"],"sourcesContent":["<template>\n <v-card>\n <v-card-title v-if=\"!loginRoute\" class=\"text-h5 bg-grey-lighten-2\">Log In</v-card-title>\n\n <v-card-text>\n <v-form onsubmit=\"return false;\" @submit.prevent=\"login\">\n <v-text-field\n id=\"\"\n v-model=\"identifier\"\n autofocus\n name=\"username\"\n label=\"Username or email\"\n prepend-icon=\"mdi-account-circle\"\n ></v-text-field>\n <v-text-field\n v-model=\"password\"\n prepend-icon=\"mdi-lock\"\n name=\"password\"\n hover=\"Show password input\"\n label=\"Enter your password\"\n hint=\"\"\n min=\"0\"\n :append-icon=\"passwordVisible ? 'mdi-eye-off' : 'mdi-eye'\"\n :type=\"passwordVisible ? 'text' : 'password'\"\n @click:append=\"() => (passwordVisible = !passwordVisible)\"\n ></v-text-field>\n\n <v-snackbar v-model=\"badLoginAttempt\" location=\"bottom right\" :timeout=\"errorTimeout\">\n {{ errorMessage }}\n <v-btn color=\"pink\" variant=\"text\" @click=\"badLoginAttempt = false\">Close</v-btn>\n </v-snackbar>\n\n <div class=\"d-flex flex-column align-start\">\n <div class=\"mb-2\">\n <v-btn class=\"mr-2\" type=\"submit\" :loading=\"awaitingResponse\" :color=\"buttonStatus.color\">\n <v-icon start>mdi-lock-open</v-icon>\n Log In\n </v-btn>\n <router-link v-if=\"loginRoute\" to=\"signup\">\n <v-btn variant=\"text\">Create New Account</v-btn>\n </router-link>\n <v-btn v-else variant=\"text\" @click=\"toggle\">Create New Account</v-btn>\n </div>\n\n <slot name=\"forgot-password\">\n <!-- Default: always show forgot password link -->\n <a\n href=\"#\"\n class=\"text-caption text-decoration-none\"\n @click.prevent=\"handleForgotPassword\"\n >\n Forgot password?\n </a>\n </slot>\n </div>\n </v-form>\n </v-card-text>\n </v-card>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ref, computed } from 'vue';\nimport { useRouter, useRoute } from 'vue-router';\nimport { alertUser } from '../SnackbarService';\nimport { log } from '@vue-skuilder/common';\nimport { Status } from '@vue-skuilder/common';\nimport { User } from '@vue-skuilder/db';\nimport { getCurrentUser, useAuthStore } from '../../stores/useAuthStore';\nimport { useConfigStore } from '../../stores/useConfigStore';\nimport { resolveLoginIdentifier } from '../../services/authAPI';\n\n// Define props\ninterface Props {\n redirectTo?: string;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n redirectTo: '/study'\n});\n\n// Define emits for toggle, cleanup, and forgot password\nconst emit = defineEmits<{\n toggle: [];\n loginSuccess: [redirectPath: string];\n forgotPassword: [];\n}>();\n\nconst router = useRouter();\nconst route = useRoute();\nconst authStore = useAuthStore();\nconst configStore = useConfigStore();\n\n// Holds a username OR an email address (see login()).\nconst identifier = ref('');\nconst password = ref('');\nconst passwordVisible = ref(false);\nconst awaitingResponse = ref(false);\nconst badLoginAttempt = ref(false);\nconst errorTimeout = ref(7000);\nconst errorMessage = ref('Username or password was incorrect.');\n\n// Shown when the email→username resolver is unreachable (route missing / 5xx /\n// network) rather than when credentials are actually wrong. Telling the two\n// apart matters: \"wrong password\" sends the user to re-check what is in fact\n// correct, and hides a real backend outage.\nconst BAD_CREDENTIALS_MSG = 'Username or password was incorrect.';\nconst LOGIN_UNAVAILABLE_MSG =\n 'Login is temporarily unavailable. Please try again in a moment.';\nconst user = ref<User | undefined>(undefined);\n\nconst loginRoute = computed(() => route.name === 'login');\n\nconst buttonStatus = computed(() => ({\n color: badLoginAttempt.value ? 'error' : 'success',\n text: badLoginAttempt.value ? 'Try again' : 'Log In',\n}));\n\nconst initBadLogin = (message: string = BAD_CREDENTIALS_MSG) => {\n errorMessage.value = message;\n badLoginAttempt.value = true;\n\n alertUser({\n text: message,\n status: Status.error,\n timeout: errorTimeout.value,\n });\n setTimeout(() => {\n badLoginAttempt.value = false;\n }, errorTimeout.value);\n};\n\nconst login = async () => {\n awaitingResponse.value = true;\n log('Starting login attempt');\n log(`Login attempt for identifier: ${identifier.value}`);\n\n try {\n log('Attempting to get User instance');\n // #172 starting point - why is the pre-existing _user being referenced here?\n user.value = await getCurrentUser();\n log('Got User instance, attempting login');\n\n // Couch _session authenticates by username only. When the identifier is an\n // email, resolve it to the account username first — server-side and gated\n // on the correct password, so it can't be used to enumerate accounts. A\n // plain username is passed straight through.\n let loginName = identifier.value;\n if (identifier.value.includes('@')) {\n const resolved = await resolveLoginIdentifier(identifier.value, password.value);\n if (!resolved.ok || !resolved.username) {\n // 401 is the server's uniform \"real auth failure\" code; anything else\n // (404 = route not deployed, 5xx, or no status = network) means the\n // resolver is unavailable, not that the credentials were wrong.\n if (resolved.status === 401) {\n log('Email identifier did not resolve: invalid credentials');\n initBadLogin();\n } else {\n log(`Email login unavailable (resolver error: ${resolved.error ?? 'network'})`);\n initBadLogin(LOGIN_UNAVAILABLE_MSG);\n }\n awaitingResponse.value = false;\n return;\n }\n loginName = resolved.username;\n }\n\n await user.value.login(loginName, password.value);\n log('Login successful');\n\n // load user config\n log('Initializing user config');\n configStore.init();\n log('User config initialized');\n\n // set login state\n log('Setting authentication state');\n authStore.loginAndRegistration.loggedIn = true;\n log(`Authentication state set, redirecting to: ${props.redirectTo}`);\n \n // Emit success event for cleanup\n emit('loginSuccess', props.redirectTo);\n \n router.push(props.redirectTo);\n log('Login and redirect complete');\n } catch (e) {\n // entry #186\n log('Login attempt failed');\n log(`Login error details: ${JSON.stringify(e)}`);\n console.log(`login error: ${JSON.stringify(e)}`);\n // - differentiate response\n // - return better message to UI\n log('Initiating bad login feedback');\n initBadLogin();\n }\n\n log('Resetting awaiting response state');\n awaitingResponse.value = false;\n};\n\n\nconst toggle = () => {\n log('Toggling registration / login forms.');\n emit('toggle');\n};\n\nconst handleForgotPassword = () => {\n log('Forgot password clicked');\n // If on login route, navigate directly\n if (loginRoute.value) {\n router.push('/request-reset');\n } else {\n // Otherwise, emit event for parent to handle (e.g., modal context)\n emit('forgotPassword');\n }\n};\n</script>\n\n<style lang=\"css\" scoped>\n.login {\n max-width: 650px;\n}\n</style>\n"],"mappings":""}
@@ -0,0 +1,155 @@
1
+ import "../../_virtual/_rolldown/runtime.mjs";
2
+ import { alertUser as e } from "../SnackbarService.mjs";
3
+ import { resolveLoginIdentifier as t } from "../../services/authAPI.mjs";
4
+ import { getCurrentUser as n, useAuthStore as r } from "../../stores/useAuthStore.mjs";
5
+ import { useConfigStore as i } from "../../stores/useConfigStore.mjs";
6
+ import { computed as a, createBlock as o, createCommentVNode as s, createElementVNode as c, createTextVNode as l, createVNode as u, defineComponent as d, openBlock as f, ref as p, renderSlot as m, resolveComponent as h, toDisplayString as g, withCtx as _, withModifiers as v } from "vue";
7
+ import { Status as y, log as b } from "@vue-skuilder/common";
8
+ import { useRoute as x, useRouter as S } from "vue-router";
9
+ //#region src/components/auth/UserLogin.vue?vue&type=script&setup=true&lang.ts
10
+ var C = { class: "d-flex flex-column align-start" }, w = { class: "mb-2" }, T = "Username or password was incorrect.", E = "Login is temporarily unavailable. Please try again in a moment.", D = /* @__PURE__ */ d({
11
+ __name: "UserLogin",
12
+ props: { redirectTo: { default: "/study" } },
13
+ emits: [
14
+ "toggle",
15
+ "loginSuccess",
16
+ "forgotPassword"
17
+ ],
18
+ setup(d, { emit: D }) {
19
+ let O = d, k = D, A = S(), j = x(), M = r(), N = i(), P = p(""), F = p(""), I = p(!1), L = p(!1), R = p(!1), z = p(7e3), B = p("Username or password was incorrect."), V = p(void 0), H = a(() => j.name === "login"), U = a(() => ({
20
+ color: R.value ? "error" : "success",
21
+ text: R.value ? "Try again" : "Log In"
22
+ })), initBadLogin = (t = T) => {
23
+ B.value = t, R.value = !0, e({
24
+ text: t,
25
+ status: y.error,
26
+ timeout: z.value
27
+ }), setTimeout(() => {
28
+ R.value = !1;
29
+ }, z.value);
30
+ }, login = async () => {
31
+ L.value = !0, b("Starting login attempt"), b(`Login attempt for identifier: ${P.value}`);
32
+ try {
33
+ b("Attempting to get User instance"), V.value = await n(), b("Got User instance, attempting login");
34
+ let e = P.value;
35
+ if (P.value.includes("@")) {
36
+ let n = await t(P.value, F.value);
37
+ if (!n.ok || !n.username) {
38
+ n.status === 401 ? (b("Email identifier did not resolve: invalid credentials"), initBadLogin()) : (b(`Email login unavailable (resolver error: ${n.error ?? "network"})`), initBadLogin(E)), L.value = !1;
39
+ return;
40
+ }
41
+ e = n.username;
42
+ }
43
+ await V.value.login(e, F.value), b("Login successful"), b("Initializing user config"), N.init(), b("User config initialized"), b("Setting authentication state"), M.loginAndRegistration.loggedIn = !0, b(`Authentication state set, redirecting to: ${O.redirectTo}`), k("loginSuccess", O.redirectTo), A.push(O.redirectTo), b("Login and redirect complete");
44
+ } catch (e) {
45
+ b("Login attempt failed"), b(`Login error details: ${JSON.stringify(e)}`), console.log(`login error: ${JSON.stringify(e)}`), b("Initiating bad login feedback"), initBadLogin();
46
+ }
47
+ b("Resetting awaiting response state"), L.value = !1;
48
+ }, toggle = () => {
49
+ b("Toggling registration / login forms."), k("toggle");
50
+ }, handleForgotPassword = () => {
51
+ b("Forgot password clicked"), H.value ? A.push("/request-reset") : k("forgotPassword");
52
+ };
53
+ return (e, t) => {
54
+ let n = h("v-card-title"), r = h("v-text-field"), i = h("v-btn"), a = h("v-snackbar"), d = h("v-icon"), p = h("router-link"), y = h("v-form"), b = h("v-card-text"), x = h("v-card");
55
+ return f(), o(x, null, {
56
+ default: _(() => [H.value ? s("", !0) : (f(), o(n, {
57
+ key: 0,
58
+ class: "text-h5 bg-grey-lighten-2"
59
+ }, {
60
+ default: _(() => t[5] || (t[5] = [l("Log In")])),
61
+ _: 1
62
+ })), u(b, null, {
63
+ default: _(() => [u(y, {
64
+ onsubmit: "return false;",
65
+ onSubmit: v(login, ["prevent"])
66
+ }, {
67
+ default: _(() => [
68
+ u(r, {
69
+ id: "",
70
+ modelValue: P.value,
71
+ "onUpdate:modelValue": t[0] || (t[0] = (e) => P.value = e),
72
+ autofocus: "",
73
+ name: "username",
74
+ label: "Username or email",
75
+ "prepend-icon": "mdi-account-circle"
76
+ }, null, 8, ["modelValue"]),
77
+ u(r, {
78
+ modelValue: F.value,
79
+ "onUpdate:modelValue": t[1] || (t[1] = (e) => F.value = e),
80
+ "prepend-icon": "mdi-lock",
81
+ name: "password",
82
+ hover: "Show password input",
83
+ label: "Enter your password",
84
+ hint: "",
85
+ min: "0",
86
+ "append-icon": I.value ? "mdi-eye-off" : "mdi-eye",
87
+ type: I.value ? "text" : "password",
88
+ "onClick:append": t[2] || (t[2] = () => I.value = !I.value)
89
+ }, null, 8, [
90
+ "modelValue",
91
+ "append-icon",
92
+ "type"
93
+ ]),
94
+ u(a, {
95
+ modelValue: R.value,
96
+ "onUpdate:modelValue": t[4] || (t[4] = (e) => R.value = e),
97
+ location: "bottom right",
98
+ timeout: z.value
99
+ }, {
100
+ default: _(() => [l(g(B.value) + " ", 1), u(i, {
101
+ color: "pink",
102
+ variant: "text",
103
+ onClick: t[3] || (t[3] = (e) => R.value = !1)
104
+ }, {
105
+ default: _(() => t[6] || (t[6] = [l("Close")])),
106
+ _: 1
107
+ })]),
108
+ _: 1
109
+ }, 8, ["modelValue", "timeout"]),
110
+ c("div", C, [c("div", w, [u(i, {
111
+ class: "mr-2",
112
+ type: "submit",
113
+ loading: L.value,
114
+ color: U.value.color
115
+ }, {
116
+ default: _(() => [u(d, { start: "" }, {
117
+ default: _(() => t[7] || (t[7] = [l("mdi-lock-open")])),
118
+ _: 1
119
+ }), t[8] || (t[8] = l(" Log In "))]),
120
+ _: 1
121
+ }, 8, ["loading", "color"]), H.value ? (f(), o(p, {
122
+ key: 0,
123
+ to: "signup"
124
+ }, {
125
+ default: _(() => [u(i, { variant: "text" }, {
126
+ default: _(() => t[9] || (t[9] = [l("Create New Account")])),
127
+ _: 1
128
+ })]),
129
+ _: 1
130
+ })) : (f(), o(i, {
131
+ key: 1,
132
+ variant: "text",
133
+ onClick: toggle
134
+ }, {
135
+ default: _(() => t[10] || (t[10] = [l("Create New Account")])),
136
+ _: 1
137
+ }))]), m(e.$slots, "forgot-password", {}, () => [c("a", {
138
+ href: "#",
139
+ class: "text-caption text-decoration-none",
140
+ onClick: v(handleForgotPassword, ["prevent"])
141
+ }, " Forgot password? ")], !0)])
142
+ ]),
143
+ _: 3
144
+ })]),
145
+ _: 3
146
+ })]),
147
+ _: 3
148
+ });
149
+ };
150
+ }
151
+ });
152
+ //#endregion
153
+ export { D as default };
154
+
155
+ //# sourceMappingURL=UserLogin.vue_vue_type_script_setup_true_lang.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserLogin.vue_vue_type_script_setup_true_lang.mjs","names":[],"sources":["../../../src/components/auth/UserLogin.vue"],"sourcesContent":["<template>\n <v-card>\n <v-card-title v-if=\"!loginRoute\" class=\"text-h5 bg-grey-lighten-2\">Log In</v-card-title>\n\n <v-card-text>\n <v-form onsubmit=\"return false;\" @submit.prevent=\"login\">\n <v-text-field\n id=\"\"\n v-model=\"identifier\"\n autofocus\n name=\"username\"\n label=\"Username or email\"\n prepend-icon=\"mdi-account-circle\"\n ></v-text-field>\n <v-text-field\n v-model=\"password\"\n prepend-icon=\"mdi-lock\"\n name=\"password\"\n hover=\"Show password input\"\n label=\"Enter your password\"\n hint=\"\"\n min=\"0\"\n :append-icon=\"passwordVisible ? 'mdi-eye-off' : 'mdi-eye'\"\n :type=\"passwordVisible ? 'text' : 'password'\"\n @click:append=\"() => (passwordVisible = !passwordVisible)\"\n ></v-text-field>\n\n <v-snackbar v-model=\"badLoginAttempt\" location=\"bottom right\" :timeout=\"errorTimeout\">\n {{ errorMessage }}\n <v-btn color=\"pink\" variant=\"text\" @click=\"badLoginAttempt = false\">Close</v-btn>\n </v-snackbar>\n\n <div class=\"d-flex flex-column align-start\">\n <div class=\"mb-2\">\n <v-btn class=\"mr-2\" type=\"submit\" :loading=\"awaitingResponse\" :color=\"buttonStatus.color\">\n <v-icon start>mdi-lock-open</v-icon>\n Log In\n </v-btn>\n <router-link v-if=\"loginRoute\" to=\"signup\">\n <v-btn variant=\"text\">Create New Account</v-btn>\n </router-link>\n <v-btn v-else variant=\"text\" @click=\"toggle\">Create New Account</v-btn>\n </div>\n\n <slot name=\"forgot-password\">\n <!-- Default: always show forgot password link -->\n <a\n href=\"#\"\n class=\"text-caption text-decoration-none\"\n @click.prevent=\"handleForgotPassword\"\n >\n Forgot password?\n </a>\n </slot>\n </div>\n </v-form>\n </v-card-text>\n </v-card>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ref, computed } from 'vue';\nimport { useRouter, useRoute } from 'vue-router';\nimport { alertUser } from '../SnackbarService';\nimport { log } from '@vue-skuilder/common';\nimport { Status } from '@vue-skuilder/common';\nimport { User } from '@vue-skuilder/db';\nimport { getCurrentUser, useAuthStore } from '../../stores/useAuthStore';\nimport { useConfigStore } from '../../stores/useConfigStore';\nimport { resolveLoginIdentifier } from '../../services/authAPI';\n\n// Define props\ninterface Props {\n redirectTo?: string;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n redirectTo: '/study'\n});\n\n// Define emits for toggle, cleanup, and forgot password\nconst emit = defineEmits<{\n toggle: [];\n loginSuccess: [redirectPath: string];\n forgotPassword: [];\n}>();\n\nconst router = useRouter();\nconst route = useRoute();\nconst authStore = useAuthStore();\nconst configStore = useConfigStore();\n\n// Holds a username OR an email address (see login()).\nconst identifier = ref('');\nconst password = ref('');\nconst passwordVisible = ref(false);\nconst awaitingResponse = ref(false);\nconst badLoginAttempt = ref(false);\nconst errorTimeout = ref(7000);\nconst errorMessage = ref('Username or password was incorrect.');\n\n// Shown when the email→username resolver is unreachable (route missing / 5xx /\n// network) rather than when credentials are actually wrong. Telling the two\n// apart matters: \"wrong password\" sends the user to re-check what is in fact\n// correct, and hides a real backend outage.\nconst BAD_CREDENTIALS_MSG = 'Username or password was incorrect.';\nconst LOGIN_UNAVAILABLE_MSG =\n 'Login is temporarily unavailable. Please try again in a moment.';\nconst user = ref<User | undefined>(undefined);\n\nconst loginRoute = computed(() => route.name === 'login');\n\nconst buttonStatus = computed(() => ({\n color: badLoginAttempt.value ? 'error' : 'success',\n text: badLoginAttempt.value ? 'Try again' : 'Log In',\n}));\n\nconst initBadLogin = (message: string = BAD_CREDENTIALS_MSG) => {\n errorMessage.value = message;\n badLoginAttempt.value = true;\n\n alertUser({\n text: message,\n status: Status.error,\n timeout: errorTimeout.value,\n });\n setTimeout(() => {\n badLoginAttempt.value = false;\n }, errorTimeout.value);\n};\n\nconst login = async () => {\n awaitingResponse.value = true;\n log('Starting login attempt');\n log(`Login attempt for identifier: ${identifier.value}`);\n\n try {\n log('Attempting to get User instance');\n // #172 starting point - why is the pre-existing _user being referenced here?\n user.value = await getCurrentUser();\n log('Got User instance, attempting login');\n\n // Couch _session authenticates by username only. When the identifier is an\n // email, resolve it to the account username first — server-side and gated\n // on the correct password, so it can't be used to enumerate accounts. A\n // plain username is passed straight through.\n let loginName = identifier.value;\n if (identifier.value.includes('@')) {\n const resolved = await resolveLoginIdentifier(identifier.value, password.value);\n if (!resolved.ok || !resolved.username) {\n // 401 is the server's uniform \"real auth failure\" code; anything else\n // (404 = route not deployed, 5xx, or no status = network) means the\n // resolver is unavailable, not that the credentials were wrong.\n if (resolved.status === 401) {\n log('Email identifier did not resolve: invalid credentials');\n initBadLogin();\n } else {\n log(`Email login unavailable (resolver error: ${resolved.error ?? 'network'})`);\n initBadLogin(LOGIN_UNAVAILABLE_MSG);\n }\n awaitingResponse.value = false;\n return;\n }\n loginName = resolved.username;\n }\n\n await user.value.login(loginName, password.value);\n log('Login successful');\n\n // load user config\n log('Initializing user config');\n configStore.init();\n log('User config initialized');\n\n // set login state\n log('Setting authentication state');\n authStore.loginAndRegistration.loggedIn = true;\n log(`Authentication state set, redirecting to: ${props.redirectTo}`);\n \n // Emit success event for cleanup\n emit('loginSuccess', props.redirectTo);\n \n router.push(props.redirectTo);\n log('Login and redirect complete');\n } catch (e) {\n // entry #186\n log('Login attempt failed');\n log(`Login error details: ${JSON.stringify(e)}`);\n console.log(`login error: ${JSON.stringify(e)}`);\n // - differentiate response\n // - return better message to UI\n log('Initiating bad login feedback');\n initBadLogin();\n }\n\n log('Resetting awaiting response state');\n awaitingResponse.value = false;\n};\n\n\nconst toggle = () => {\n log('Toggling registration / login forms.');\n emit('toggle');\n};\n\nconst handleForgotPassword = () => {\n log('Forgot password clicked');\n // If on login route, navigate directly\n if (loginRoute.value) {\n router.push('/request-reset');\n } else {\n // Otherwise, emit event for parent to handle (e.g., modal context)\n emit('forgotPassword');\n }\n};\n</script>\n\n<style lang=\"css\" scoped>\n.login {\n max-width: 650px;\n}\n</style>\n"],"mappings":";;;;;;;;;4EAyGM,IAAsB,uCACtB,IACJ;;;;;;;;;EA/BF,IAAM,IAAQ,GAKR,IAAO,GAMP,IAAS,GAAW,EACpB,IAAQ,GAAU,EAClB,IAAY,GAAc,EAC1B,IAAc,GAAgB,EAG9B,IAAa,EAAI,GAAG,EACpB,IAAW,EAAI,GAAG,EAClB,IAAkB,EAAI,GAAM,EAC5B,IAAmB,EAAI,GAAM,EAC7B,IAAkB,EAAI,GAAM,EAC5B,IAAe,EAAI,IAAK,EACxB,IAAe,EAAI,sCAAsC,EASzD,IAAO,EAAsB,KAAA,EAAU,EAEvC,IAAa,QAAe,EAAM,SAAS,QAAQ,EAEnD,IAAe,SAAgB;GACnC,OAAO,EAAgB,QAAQ,UAAU;GACzC,MAAM,EAAgB,QAAQ,cAAc;GAC7C,EAAE,EAEG,gBAAgB,IAAkB,MAAwB;AAS9D,GARA,EAAa,QAAQ,GACrB,EAAgB,QAAQ,IAExB,EAAU;IACR,MAAM;IACN,QAAQ,EAAO;IACf,SAAS,EAAa;IACvB,CAAC,EACF,iBAAiB;AACf,MAAgB,QAAQ;MACvB,EAAa,MAAM;KAGlB,QAAQ,YAAY;AAGxB,GAFA,EAAiB,QAAQ,IACzB,EAAI,yBAAyB,EAC7B,EAAI,iCAAiC,EAAW,QAAQ;AAExD,OAAI;AAIF,IAHA,EAAI,kCAAkC,EAEtC,EAAK,QAAQ,MAAM,GAAgB,EACnC,EAAI,sCAAsC;IAM1C,IAAI,IAAY,EAAW;AAC3B,QAAI,EAAW,MAAM,SAAS,IAAI,EAAE;KAClC,IAAM,IAAW,MAAM,EAAuB,EAAW,OAAO,EAAS,MAAM;AAC/E,SAAI,CAAC,EAAS,MAAM,CAAC,EAAS,UAAU;AAWtC,MAPI,EAAS,WAAW,OACtB,EAAI,wDAAwD,EAC5D,cAAc,KAEd,EAAI,4CAA4C,EAAS,SAAS,UAAU,GAAG,EAC/E,aAAa,EAAsB,GAErC,EAAiB,QAAQ;AACzB;;AAEF,SAAY,EAAS;;AAoBvB,IAjBA,MAAM,EAAK,MAAM,MAAM,GAAW,EAAS,MAAM,EACjD,EAAI,mBAAmB,EAGvB,EAAI,2BAA2B,EAC/B,EAAY,MAAM,EAClB,EAAI,0BAA0B,EAG9B,EAAI,+BAA+B,EACnC,EAAU,qBAAqB,WAAW,IAC1C,EAAI,6CAA6C,EAAM,aAAa,EAGpE,EAAK,gBAAgB,EAAM,WAAW,EAEtC,EAAO,KAAK,EAAM,WAAW,EAC7B,EAAI,8BAA8B;YAC3B,GAAG;AAQV,IANA,EAAI,uBAAuB,EAC3B,EAAI,wBAAwB,KAAK,UAAU,EAAE,GAAG,EAChD,QAAQ,IAAI,gBAAgB,KAAK,UAAU,EAAE,GAAG,EAGhD,EAAI,gCAAgC,EACpC,cAAc;;AAIhB,GADA,EAAI,oCAAoC,EACxC,EAAiB,QAAQ;KAIrB,eAAe;AAEnB,GADA,EAAI,uCAAuC,EAC3C,EAAK,SAAS;KAGV,6BAA6B;AAGjC,GAFA,EAAI,0BAA0B,EAE1B,EAAW,QACb,EAAO,KAAK,iBAAiB,GAG7B,EAAK,iBAAiB"}
@@ -0,0 +1,9 @@
1
+ import e from "../../_virtual/_plugin-vue_export-helper.mjs";
2
+ import t from "./UserLoginAndRegistrationContainer.vue_vue_type_script_setup_true_lang.mjs";
3
+ /* empty css */
4
+ //#region src/components/auth/UserLoginAndRegistrationContainer.vue
5
+ var n = /* @__PURE__ */ e(t, [["__scopeId", "data-v-5a55bdf0"]]);
6
+ //#endregion
7
+ export { n as default };
8
+
9
+ //# sourceMappingURL=UserLoginAndRegistrationContainer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserLoginAndRegistrationContainer.mjs","names":[],"sources":["../../../src/components/auth/UserLoginAndRegistrationContainer.vue"],"sourcesContent":["<template>\n <div v-if=\"userReady && display\">\n <transition name=\"component-fade\" mode=\"out-in\">\n <div v-if=\"guestMode\" key=\"login-buttons\">\n <!-- Registration button: only if showLoginRegistration is true -->\n <v-dialog v-model=\"regDialog\" width=\"500px\" v-if=\"authUIConfig.showLoginRegistration\">\n <template #activator=\"{ props }\">\n <v-btn class=\"mr-2\" size=\"small\" color=\"success\" v-bind=\"props\">Sign Up</v-btn>\n </template>\n <UserRegistration\n @toggle=\"toggle\"\n @signup-success=\"handleSignupSuccess\"\n :on-signup-success=\"handleSignupSuccess\"\n />\n </v-dialog>\n \n <!-- Login button: always show in guest mode -->\n <v-dialog v-model=\"loginDialog\" width=\"500px\">\n <template #activator=\"{ props }\">\n <v-btn size=\"small\" color=\"success\" v-bind=\"props\">Log In</v-btn>\n </template>\n <UserLogin @toggle=\"toggle\" @forgot-password=\"openResetDialog\" />\n </v-dialog>\n\n <!-- Password reset dialog: opened from login via \"Forgot password?\" -->\n <v-dialog v-model=\"resetDialog\" width=\"500px\">\n <RequestPasswordReset @cancel=\"closeResetDialog\" @success=\"closeResetDialog\" />\n </v-dialog>\n </div>\n <div v-else key=\"user-chip\">\n <user-chip />\n </div>\n </transition>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { computed, onMounted, ref } from 'vue';\nimport { useRoute } from 'vue-router';\nimport UserLogin from './UserLogin.vue';\nimport UserRegistration from './UserRegistration.vue';\nimport RequestPasswordReset from './RequestPasswordReset.vue';\nimport UserChip from './UserChip.vue';\nimport { useAuthStore } from '../../stores/useAuthStore';\nimport { useAuthUI } from '../../composables/useAuthUI';\nimport { GuestUsername } from '@vue-skuilder/db';\n\n// Define props\nconst props = defineProps<{\n showLoginButton?: boolean;\n redirectToPath?: string;\n showRegistration?: boolean;\n onSignupSuccess?: (payload: { username: string }) => void;\n}>();\n\n// Define emits (keeping for backward compatibility if needed)\nconst emit = defineEmits<{\n 'signup-success': [payload: { username: string }]\n}>();\n\nconst route = useRoute();\nconst authStore = useAuthStore();\nconst authUI = useAuthUI();\n\n// Initialize auth UI detection\nonMounted(async () => {\n await authUI.detectSyncStrategy();\n});\n\nconst display = computed(() => {\n if (!route.name || typeof route.name !== 'string') {\n return true;\n }\n const routeName = route.name.toLowerCase();\n return !(routeName === 'login' || routeName === 'signup');\n});\n\nconst userReady = computed(() => authStore.onLoadComplete);\n\nconst guestMode = computed(() => {\n if (authStore._user) {\n return authStore._user.getUsername().startsWith(GuestUsername);\n }\n return !authStore.loginAndRegistration.loggedIn;\n});\n\nconst authUIConfig = computed(() => {\n const baseConfig = authUI.config.value || {\n showLoginRegistration: true,\n showLogout: true, \n showResetData: false,\n logoutLabel: 'Log out',\n resetLabel: '',\n };\n \n // Apply prop overrides\n return {\n ...baseConfig,\n ...(props.showRegistration !== undefined && { showLoginRegistration: props.showRegistration })\n };\n});\n\nconst regDialog = computed({\n get: () => authStore.loginAndRegistration.regDialogOpen,\n set: (value: boolean) => {\n authStore.loginAndRegistration.regDialogOpen = value;\n },\n});\n\nconst loginDialog = computed({\n get: () => authStore.loginAndRegistration.loginDialogOpen,\n set: (value: boolean) => {\n authStore.loginAndRegistration.loginDialogOpen = value;\n },\n});\n\n// Password reset dialog state (local, not in auth store)\nconst resetDialog = ref(false);\n\nconst toggle = () => {\n if (regDialog.value && loginDialog.value) {\n throw new Error('Registration / Login dialogs both activated.');\n } else if (regDialog.value === loginDialog.value) {\n throw new Error('Registration / Login dialogs toggled while both were dormant.');\n } else {\n regDialog.value = !regDialog.value;\n loginDialog.value = !loginDialog.value;\n }\n};\n\nconst openResetDialog = () => {\n loginDialog.value = false; // Close login dialog\n resetDialog.value = true; // Open reset dialog\n};\n\nconst closeResetDialog = () => {\n resetDialog.value = false;\n};\n\nconst handleSignupSuccess = (payload: { username: string }) => {\n // Close the registration dialog\n regDialog.value = false;\n\n // Call the callback prop if provided (preferred method)\n if (props.onSignupSuccess) {\n props.onSignupSuccess(payload);\n }\n\n // Also emit event for backward compatibility\n emit('signup-success', payload);\n};\n</script>\n\n<style scoped>\n.component-fade-enter-active,\n.component-fade-leave-active {\n transition: opacity 0.5s ease;\n}\n.component-fade-enter,\n.component-fade-leave-to {\n opacity: 0;\n}\n</style>\n"],"mappings":""}
@@ -0,0 +1,126 @@
1
+ import "../../_virtual/_rolldown/runtime.mjs";
2
+ import { useAuthStore as e } from "../../stores/useAuthStore.mjs";
3
+ import { useAuthUI as t } from "../../composables/useAuthUI.mjs";
4
+ import n from "./UserChip.mjs";
5
+ import r from "./UserLogin.mjs";
6
+ import i from "./UserRegistration.mjs";
7
+ import a from "./RequestPasswordReset.mjs";
8
+ import { Transition as o, computed as s, createBlock as c, createCommentVNode as l, createElementBlock as u, createTextVNode as d, createVNode as f, defineComponent as p, mergeProps as m, onMounted as h, openBlock as g, ref as _, resolveComponent as v, withCtx as y } from "vue";
9
+ import { GuestUsername as b } from "@vue-skuilder/db";
10
+ import { useRoute as x } from "vue-router";
11
+ //#region src/components/auth/UserLoginAndRegistrationContainer.vue?vue&type=script&setup=true&lang.ts
12
+ var S = { key: 0 }, C = { key: "login-buttons" }, w = { key: "user-chip" }, T = /* @__PURE__ */ p({
13
+ __name: "UserLoginAndRegistrationContainer",
14
+ props: {
15
+ showLoginButton: { type: Boolean },
16
+ redirectToPath: {},
17
+ showRegistration: { type: Boolean },
18
+ onSignupSuccess: { type: Function }
19
+ },
20
+ emits: ["signup-success"],
21
+ setup(p, { emit: T }) {
22
+ let E = p, D = T, O = x(), k = e(), A = t();
23
+ h(async () => {
24
+ await A.detectSyncStrategy();
25
+ });
26
+ let j = s(() => {
27
+ if (!O.name || typeof O.name != "string") return !0;
28
+ let e = O.name.toLowerCase();
29
+ return !(e === "login" || e === "signup");
30
+ }), M = s(() => k.onLoadComplete), N = s(() => k._user ? k._user.getUsername().startsWith(b) : !k.loginAndRegistration.loggedIn), P = s(() => ({
31
+ ...A.config.value || {
32
+ showLoginRegistration: !0,
33
+ showLogout: !0,
34
+ showResetData: !1,
35
+ logoutLabel: "Log out",
36
+ resetLabel: ""
37
+ },
38
+ ...E.showRegistration !== void 0 && { showLoginRegistration: E.showRegistration }
39
+ })), F = s({
40
+ get: () => k.loginAndRegistration.regDialogOpen,
41
+ set: (e) => {
42
+ k.loginAndRegistration.regDialogOpen = e;
43
+ }
44
+ }), I = s({
45
+ get: () => k.loginAndRegistration.loginDialogOpen,
46
+ set: (e) => {
47
+ k.loginAndRegistration.loginDialogOpen = e;
48
+ }
49
+ }), L = _(!1), toggle = () => {
50
+ if (F.value && I.value) throw Error("Registration / Login dialogs both activated.");
51
+ if (F.value === I.value) throw Error("Registration / Login dialogs toggled while both were dormant.");
52
+ F.value = !F.value, I.value = !I.value;
53
+ }, openResetDialog = () => {
54
+ I.value = !1, L.value = !0;
55
+ }, closeResetDialog = () => {
56
+ L.value = !1;
57
+ }, handleSignupSuccess = (e) => {
58
+ F.value = !1, E.onSignupSuccess && E.onSignupSuccess(e), D("signup-success", e);
59
+ };
60
+ return (e, t) => {
61
+ let s = v("v-btn"), p = v("v-dialog");
62
+ return M.value && j.value ? (g(), u("div", S, [f(o, {
63
+ name: "component-fade",
64
+ mode: "out-in"
65
+ }, {
66
+ default: y(() => [N.value ? (g(), u("div", C, [
67
+ P.value.showLoginRegistration ? (g(), c(p, {
68
+ key: 0,
69
+ modelValue: F.value,
70
+ "onUpdate:modelValue": t[0] || (t[0] = (e) => F.value = e),
71
+ width: "500px"
72
+ }, {
73
+ activator: y(({ props: e }) => [f(s, m({
74
+ class: "mr-2",
75
+ size: "small",
76
+ color: "success"
77
+ }, e), {
78
+ default: y(() => t[3] || (t[3] = [d("Sign Up")])),
79
+ _: 2
80
+ }, 1040)]),
81
+ default: y(() => [f(i, {
82
+ onToggle: toggle,
83
+ onSignupSuccess: handleSignupSuccess,
84
+ "on-signup-success": handleSignupSuccess
85
+ })]),
86
+ _: 1
87
+ }, 8, ["modelValue"])) : l("", !0),
88
+ f(p, {
89
+ modelValue: I.value,
90
+ "onUpdate:modelValue": t[1] || (t[1] = (e) => I.value = e),
91
+ width: "500px"
92
+ }, {
93
+ activator: y(({ props: e }) => [f(s, m({
94
+ size: "small",
95
+ color: "success"
96
+ }, e), {
97
+ default: y(() => t[4] || (t[4] = [d("Log In")])),
98
+ _: 2
99
+ }, 1040)]),
100
+ default: y(() => [f(r, {
101
+ onToggle: toggle,
102
+ onForgotPassword: openResetDialog
103
+ })]),
104
+ _: 1
105
+ }, 8, ["modelValue"]),
106
+ f(p, {
107
+ modelValue: L.value,
108
+ "onUpdate:modelValue": t[2] || (t[2] = (e) => L.value = e),
109
+ width: "500px"
110
+ }, {
111
+ default: y(() => [f(a, {
112
+ onCancel: closeResetDialog,
113
+ onSuccess: closeResetDialog
114
+ })]),
115
+ _: 1
116
+ }, 8, ["modelValue"])
117
+ ])) : (g(), u("div", w, [f(n)]))]),
118
+ _: 1
119
+ })])) : l("", !0);
120
+ };
121
+ }
122
+ });
123
+ //#endregion
124
+ export { T as default };
125
+
126
+ //# sourceMappingURL=UserLoginAndRegistrationContainer.vue_vue_type_script_setup_true_lang.mjs.map