SignInDialog.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. <template>
  2. <div>
  3. <Form
  4. class="flex flex-col gap-2 p-5"
  5. v-slot="$form"
  6. :initialValues="initialValues"
  7. :resolver="resolver"
  8. :validateOnValueUpdate="false"
  9. :validateOnBlur="true"
  10. @submit="onFormSubmit"
  11. >
  12. <div class="flex flex-col">
  13. <label
  14. for="signin_email"
  15. class="ml-1 text-sm text-primary dark:text-primary"
  16. >
  17. Email Address
  18. </label>
  19. <InputText
  20. name="email"
  21. fluid
  22. id="signin_email"
  23. type="email"
  24. placeholder="Email address"
  25. autocomplete="email"
  26. autofocus
  27. />
  28. <Message
  29. v-if="$form.email?.invalid"
  30. severity="error"
  31. size="small"
  32. variant="simple"
  33. >
  34. {{ $form.email?.error?.message }}
  35. </Message>
  36. </div>
  37. <div class="flex flex-col">
  38. <label
  39. for="signin_password"
  40. class="ml-1 text-sm text-primary dark:text-primary"
  41. >
  42. Password
  43. </label>
  44. <Password
  45. name="password"
  46. :feedback="false"
  47. fluid
  48. inputId="signin_password"
  49. toggleMask
  50. autocomplete="current-password"
  51. placeholder="Password"
  52. >
  53. <template #maskicon="{ toggleCallback }">
  54. <Icon
  55. class="absolute inset-e-3 top-1/2 -mt-2 h-4 w-4 text-surface-500
  56. dark:text-surface-400"
  57. name="ph:eye-slash-bold"
  58. @click="toggleCallback"
  59. />
  60. </template>
  61. <template #unmaskicon="{ toggleCallback }">
  62. <Icon
  63. class="absolute inset-e-3 top-1/2 -mt-2 h-4 w-4 text-surface-500
  64. dark:text-surface-400"
  65. name="ph:eye-bold"
  66. @click="toggleCallback"
  67. />
  68. </template>
  69. </Password>
  70. <Message
  71. v-if="$form.password?.invalid"
  72. severity="error"
  73. size="small"
  74. variant="simple"
  75. >
  76. {{ $form.password?.error?.message }}
  77. </Message>
  78. </div>
  79. <Button
  80. label="Sign In"
  81. type="submit"
  82. fluid
  83. :disabled="!$form.valid"
  84. :loading="isLoading"
  85. class="mt-5"
  86. >
  87. <template #icon>
  88. <Icon name="ph:sign-in-bold" />
  89. </template>
  90. <template #loadingicon>
  91. <Icon
  92. class="animate-spin"
  93. name="ph:circle-notch-bold"
  94. />
  95. </template>
  96. </Button>
  97. </Form>
  98. <div class="flex flex-col p-5 pt-0">
  99. <Button
  100. variant="text"
  101. @click="resetPasswordRequest()"
  102. >
  103. Forgot Password
  104. </Button>
  105. </div>
  106. </div>
  107. </template>
  108. <script setup>
  109. import { zodResolver } from "@primeuix/forms/resolvers/zod"
  110. import { hydrateOnVisible } from "vue"
  111. const ResetPasswordRequestDialog = defineAsyncComponent({
  112. loader: () => import("~/components/ResetPasswordRequestDialog.vue"),
  113. hydrate: hydrateOnVisible()
  114. })
  115. const { signIn } = useAuthClient()
  116. const dynamicDialog = useDynamicDialog()
  117. const toast = useToast()
  118. const dialogRef = inject("dialogRef")
  119. const resolver = ref(
  120. zodResolver(
  121. z.object({
  122. email: z.email("Not an email address."),
  123. password: z.string().min(1, "Password is required.")
  124. })
  125. )
  126. )
  127. const isLoading = ref(false)
  128. const initialValues = ref({ email: "", password: "" })
  129. async function onFormSubmit({ valid, values }) {
  130. if (valid) {
  131. await signInWithPassword(values)
  132. closeDialog()
  133. }
  134. }
  135. async function signInWithPassword(values) {
  136. if (isLoading.value) {
  137. return
  138. }
  139. isLoading.value = true
  140. const { error } = await signIn(values)
  141. isLoading.value = false
  142. if (error) {
  143. console.error(error)
  144. toast.add({
  145. severity: "error",
  146. summary: "SignIn Error.",
  147. detail: error.data?.message || error.message
  148. })
  149. } else {
  150. toast.add({
  151. severity: "success",
  152. summary: "Signed In.",
  153. detail: "You are now signed in.",
  154. life: 3000
  155. })
  156. }
  157. }
  158. async function resetPasswordRequest() {
  159. closeDialog()
  160. // noinspection JSUnresolvedReference
  161. dynamicDialog.open(ResetPasswordRequestDialog)
  162. }
  163. function closeDialog() {
  164. dialogRef.value.close()
  165. }
  166. </script>
  167. <style scoped></style>