LoginPage.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <template>
  2. <q-page class="login-page column items-center justify-center">
  3. <div class="login-overlay" />
  4. <div class="login-card column items-center">
  5. <div class="column items-center fields-card">
  6. <q-img :src="Logo" class="login-logo q-mb-xl" />
  7. <q-form
  8. ref="formRef"
  9. class="full-width"
  10. autocorrect="off"
  11. autocapitalize="off"
  12. autocomplete="off"
  13. spellcheck="false"
  14. @submit="onSubmit"
  15. >
  16. <DefaultInput
  17. v-model="form.email"
  18. v-model:error="validationErrors.email"
  19. type="email"
  20. autofocus
  21. color="violet-normal"
  22. :rules="[inputRules.required, inputRules.email]"
  23. :label="$t('common.terms.email')"
  24. lazy-rules
  25. >
  26. <template #append>
  27. <q-icon name="mdi-account-outline" color="grey-5" />
  28. </template>
  29. </DefaultInput>
  30. <DefaultPasswordInput
  31. v-model="form.password"
  32. v-model:error="validationErrors.password"
  33. :rules="[inputRules.required, inputRules.min(6)]"
  34. lazy-rules
  35. :label="$t('common.terms.password')"
  36. />
  37. <q-checkbox
  38. v-model="checkbox"
  39. size="xs"
  40. :label="$t('auth.remember_email') || 'Lembrar e-mail'"
  41. class="q-mb-md"
  42. style="margin-left: -6px"
  43. />
  44. <q-btn
  45. class="full-width q-mt-sm login-btn"
  46. color="violet-normal"
  47. :label="$t('auth.sign-in')"
  48. type="submit"
  49. unelevated
  50. :loading
  51. >
  52. <template #loading>
  53. <q-spinner />
  54. </template>
  55. </q-btn>
  56. </q-form>
  57. <a
  58. href="#"
  59. class="forgot-link q-mt-md"
  60. @click.prevent="router.push({ name: 'ForgotPasswordPage' })"
  61. >
  62. {{ $t("auth.forgot_password") }}
  63. </a>
  64. <q-btn
  65. flat
  66. no-caps
  67. dense
  68. class="q-mt-lg privacy-link"
  69. :label="$t('common.terms.privacy_policy')"
  70. @click="openUrl(PRIVACY_POLICY_URL)"
  71. />
  72. </div>
  73. </div>
  74. </q-page>
  75. </template>
  76. <script setup>
  77. import { ref, onBeforeMount, useTemplateRef } from "vue";
  78. import { useQuasar } from "quasar";
  79. import { useAuth } from "src/composables/useAuth";
  80. import { useRouter } from "vue-router";
  81. import { useInputRules } from "src/composables/useInputRules";
  82. import { useSubmitHandler } from "src/composables/useSubmitHandler";
  83. import Logo from "src/assets/logo_serprati.svg";
  84. import DefaultInput from "src/components/defaults/DefaultInput.vue";
  85. import DefaultPasswordInput from "src/components/defaults/DefaultPasswordInput.vue";
  86. const PRIVACY_POLICY_URL = "https://politicas.softpar.inf.br/politicas/politicaSerpRatiAssociado.html";
  87. const openUrl = (url) => window.open(url, "_blank");
  88. const router = useRouter();
  89. const $q = useQuasar();
  90. const { inputRules } = useInputRules();
  91. const { login } = useAuth();
  92. const formRef = useTemplateRef("formRef");
  93. const {
  94. loading,
  95. validationErrors,
  96. execute: submitForm,
  97. } = useSubmitHandler({
  98. onSuccess: () => router.push({ name: "CarteirinhaPage" }),
  99. formRef,
  100. });
  101. const form = ref({
  102. email: null,
  103. password: process.env.PASSWORD ?? null,
  104. });
  105. const checkbox = ref(false);
  106. const onSubmit = async () => {
  107. await submitForm(() => login(form.value.email, form.value.password));
  108. const email_storage = $q.cookies.get("email");
  109. if (email_storage && !checkbox.value) {
  110. $q.cookies.remove("email");
  111. }
  112. if (checkbox.value) {
  113. $q.cookies.set("email", form.value.email, {
  114. path: "/",
  115. sameSite: "Lax",
  116. });
  117. }
  118. };
  119. onBeforeMount(() => {
  120. const email_storage = $q.cookies.get("email");
  121. if (email_storage) {
  122. checkbox.value = true;
  123. form.value.email = email_storage;
  124. }
  125. });
  126. </script>
  127. <style lang="scss" scoped>
  128. @use "sass:map";
  129. @use "src/css/quasar.variables.scss" as *;
  130. .login-page {
  131. min-height: 100dvh;
  132. background-image: url("src/assets/pessoas_fundo.jpg");
  133. background-size: cover;
  134. background-position: center;
  135. position: relative;
  136. }
  137. .login-overlay {
  138. position: absolute;
  139. inset: 0;
  140. background: rgba(74, 20, 140, 0.48);
  141. z-index: 0;
  142. }
  143. .login-card {
  144. z-index: 1;
  145. display: flex;
  146. align-items: center;
  147. justify-content: center;
  148. width: calc(100% - 32px);
  149. min-height: calc(100dvh - 32px);
  150. background: rgba(255, 255, 255, 0.747);
  151. border-radius: 16px;
  152. box-shadow: 0 4px 32px rgba(0, 0, 0, 0.15);
  153. padding-top: env(safe-area-inset-top);
  154. padding-bottom: env(safe-area-inset-bottom);
  155. }
  156. .fields-card {
  157. width: 100%;
  158. max-width: 400px;
  159. padding: 32px;
  160. border-radius: 12px;
  161. // Texto digitado visível em todos os estados
  162. :deep(.q-field__native),
  163. :deep(.q-field__input) {
  164. color: $color-text !important;
  165. }
  166. // Fundo opaco branco (evita herdar transparência do card)
  167. :deep(.q-field__control) {
  168. background: $surface !important;
  169. }
  170. // Label padrão (sem foco)
  171. :deep(.q-field__label) {
  172. color: $color-text-2;
  173. }
  174. // Label quando focado
  175. :deep(.q-field--focused .q-field__label) {
  176. color: $violet-normal;
  177. }
  178. // Label quando tem conteúdo mas sem foco (blur com valor)
  179. :deep(.q-field--float:not(.q-field--focused) .q-field__label) {
  180. color: $neutral-dark-active;
  181. }
  182. }
  183. .login-logo {
  184. width: 280px;
  185. max-width: 100%;
  186. }
  187. .login-btn {
  188. height: 44px;
  189. font-size: 15px;
  190. font-weight: 600;
  191. letter-spacing: 0.5px;
  192. }
  193. .forgot-link {
  194. color: map.get($colors, "violet-normal");
  195. font-size: 13px;
  196. text-decoration: none;
  197. cursor: pointer;
  198. &:hover {
  199. color: map.get($colors, "violet-normal-hover");
  200. text-decoration: underline;
  201. }
  202. }
  203. .privacy-link {
  204. font-size: 12px;
  205. color: rgba(74, 20, 140, 0.65);
  206. text-decoration: underline;
  207. }
  208. </style>