|
|
@@ -1,68 +1,135 @@
|
|
|
<template>
|
|
|
- <q-page class="login-page bg-surface-dark">
|
|
|
- <Transition name="fade-slide" mode="out-in">
|
|
|
-
|
|
|
- <div v-if="!clicked" key="splash" class="splash-screen" @click="clicked = true">
|
|
|
- <img :src="BackgroundLogin" class="splash-layer splash-layer--bg" />
|
|
|
- <img :src="FotoDiarista" class="splash-layer splash-layer--photo" />
|
|
|
- <img :src="LogoLogin" class="splash-layer splash-layer--logo" />
|
|
|
+ <q-page class="bg-surface-dark login-page">
|
|
|
+ <Transition mode="out-in" name="fade-slide">
|
|
|
+ <div
|
|
|
+ v-if="!clicked"
|
|
|
+ key="splash"
|
|
|
+ class="splash-screen"
|
|
|
+ @click="clicked = true"
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ class="splash-layer splash-layer--bg"
|
|
|
+ :src="BackgroundLogin"
|
|
|
+ />
|
|
|
+
|
|
|
+ <img
|
|
|
+ class="splash-layer splash-layer--photo"
|
|
|
+ :src="FotoDiarista"
|
|
|
+ />
|
|
|
+
|
|
|
+ <img
|
|
|
+ class="splash-layer splash-layer--logo"
|
|
|
+ :src="LogoLogin"
|
|
|
+ />
|
|
|
</div>
|
|
|
|
|
|
- <div v-else-if="steps === 4" key="step4" class="splash-screen">
|
|
|
- <img :src="BackgroundLogin" class="splash-layer splash-layer--bg" />
|
|
|
- <img :src="FotoDiarista" class="splash-layer splash-layer--photo" />
|
|
|
- <img :src="LogoLogin" class="splash-layer splash-layer--logo-small" />
|
|
|
+ <div
|
|
|
+ v-else-if="steps === 5"
|
|
|
+ key="step5"
|
|
|
+ class="splash-screen"
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ class="splash-layer splash-layer--bg"
|
|
|
+ :src="BackgroundLogin"
|
|
|
+ />
|
|
|
+
|
|
|
+ <img
|
|
|
+ class="splash-layer splash-layer--photo"
|
|
|
+ :src="FotoDiarista"
|
|
|
+ />
|
|
|
+
|
|
|
+ <img
|
|
|
+ class="splash-layer splash-layer--logo-small"
|
|
|
+ :src="LogoLogin"
|
|
|
+ />
|
|
|
+
|
|
|
<div class="step4-card-wrapper">
|
|
|
<LoginStepFourPanel
|
|
|
- @back="steps = 3"
|
|
|
+ @back="goBack"
|
|
|
@cep-resolved="onCepResolved"
|
|
|
@device-location="onDeviceLocation"
|
|
|
/>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <div v-else key="flow" class="flow-screen">
|
|
|
-
|
|
|
- <div class="flow-header">
|
|
|
+ <div
|
|
|
+ v-else
|
|
|
+ key="flow"
|
|
|
+ class="flow-screen"
|
|
|
+ >
|
|
|
+ <div class="flow-header items-center row">
|
|
|
<q-btn
|
|
|
- v-if="steps === 3"
|
|
|
- flat
|
|
|
+ v-if="steps >= 4"
|
|
|
+ color="primary"
|
|
|
dense
|
|
|
+ flat
|
|
|
+ icon="mdi-arrow-left"
|
|
|
+ round
|
|
|
+ @click="goBack"
|
|
|
+ />
|
|
|
+
|
|
|
+ <q-btn
|
|
|
+ v-else-if="steps === 3"
|
|
|
+ class="q-ml-auto"
|
|
|
color="primary"
|
|
|
- :label="$t('auth.register_later')"
|
|
|
+ dense
|
|
|
+ flat
|
|
|
icon-right="mdi-chevron-right-circle-outline"
|
|
|
- class=""
|
|
|
- @click="steps = 4"
|
|
|
+ :label="$t('auth.register_later')"
|
|
|
+ @click="steps = 5"
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
<div class="flow-logo">
|
|
|
- <q-img :src="LogoDiariaCampos" style="max-width: 180px;" />
|
|
|
+ <q-img
|
|
|
+ style="max-width: 180px"
|
|
|
+ :src="LogoDiariaCampos"
|
|
|
+ />
|
|
|
</div>
|
|
|
|
|
|
<q-form
|
|
|
ref="loginForm"
|
|
|
- class="flow-form"
|
|
|
- autocorrect="off"
|
|
|
autocapitalize="off"
|
|
|
autocomplete="off"
|
|
|
+ autocorrect="off"
|
|
|
+ class="flow-form"
|
|
|
spellcheck="false"
|
|
|
@submit="onSubmit"
|
|
|
>
|
|
|
- <div class="flow-content" :class="{ 'flow-content--centered': steps < 3 }">
|
|
|
- <LoginStepOnePanel v-if="steps === 1" v-model:email="email" v-model:phone="phone" />
|
|
|
- <LoginStepTwoPanel v-else-if="steps === 2" v-model:code="code" />
|
|
|
- <LoginStepThreePanel v-else-if="steps === 3" v-model="stepThreeForm" />
|
|
|
+ <div
|
|
|
+ class="flow-content"
|
|
|
+ :class="{ 'flow-content--centered': steps < 3 }"
|
|
|
+ >
|
|
|
+ <LoginStepOnePanel
|
|
|
+ v-if="steps === 1"
|
|
|
+ v-model:email="email"
|
|
|
+ v-model:phone="phone"
|
|
|
+ />
|
|
|
+
|
|
|
+ <LoginStepTwoPanel
|
|
|
+ v-else-if="steps === 2"
|
|
|
+ v-model:code="code"
|
|
|
+ />
|
|
|
+
|
|
|
+ <LoginStepThreePanel
|
|
|
+ v-else-if="steps === 3"
|
|
|
+ v-model="stepThreeForm"
|
|
|
+ />
|
|
|
+
|
|
|
+ <LoginStepAvatarPanel
|
|
|
+ v-else-if="steps === 4"
|
|
|
+ v-model="stepAvatarForm"
|
|
|
+ />
|
|
|
</div>
|
|
|
|
|
|
<div class="flow-footer">
|
|
|
<q-btn
|
|
|
+ class="full-width"
|
|
|
color="primary-button"
|
|
|
- :label="$t('auth.continue')"
|
|
|
- rounded
|
|
|
padding="8px 12px"
|
|
|
+ rounded
|
|
|
type="submit"
|
|
|
- class="full-width"
|
|
|
+ :label="$t('auth.continue')"
|
|
|
:loading="submitting"
|
|
|
>
|
|
|
<template #loading>
|
|
|
@@ -71,113 +138,78 @@
|
|
|
</q-btn>
|
|
|
</div>
|
|
|
</q-form>
|
|
|
-
|
|
|
</div>
|
|
|
-
|
|
|
</Transition>
|
|
|
</q-page>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { onMounted, ref } from 'vue';
|
|
|
-import { createUserAndClient, sendCode, validateCode } from 'src/api/user';
|
|
|
-import { useAuth } from 'src/composables/useAuth';
|
|
|
-import { useRouter } from 'vue-router';
|
|
|
-import { useRegistrationFlowStore } from 'src/stores/registrationFlow';
|
|
|
-
|
|
|
-import BackgroundLogin from 'src/assets/background-login.svg';
|
|
|
-import FotoDiarista from 'src/assets/foto_diarista_login.svg';
|
|
|
-import LogoLogin from 'src/assets/logo_diaria_login.svg';
|
|
|
-import LogoDiariaCampos from 'src/assets/logo_diaria_campos_login.svg';
|
|
|
-
|
|
|
-import LoginStepOnePanel from 'src/components/login/LoginStepOnePanel.vue';
|
|
|
-import LoginStepTwoPanel from 'src/components/login/LoginStepTwoPanel.vue';
|
|
|
-import LoginStepThreePanel from 'src/components/login/LoginStepThreePanel.vue';
|
|
|
-import LoginStepFourPanel from 'src/components/login/LoginStepFourPanel.vue';
|
|
|
+import { createUserAndClient, sendCode, validateCode } from "src/api/user";
|
|
|
+import { useAuth } from "src/composables/useAuth";
|
|
|
+import { useRegistrationFlowStore } from "src/stores/registrationFlow";
|
|
|
+import { onMounted, ref } from "vue";
|
|
|
+import { useRouter } from "vue-router";
|
|
|
+
|
|
|
+import BackgroundLogin from "src/assets/background-login.svg";
|
|
|
+import FotoDiarista from "src/assets/foto_diarista_login.svg";
|
|
|
+import LogoDiariaCampos from "src/assets/logo_diaria_campos_login.svg";
|
|
|
+import LogoLogin from "src/assets/logo_diaria_login.svg";
|
|
|
+
|
|
|
+import LoginStepAvatarPanel from "src/components/login/LoginStepAvatarPanel.vue";
|
|
|
+import LoginStepFourPanel from "src/components/login/LoginStepFourPanel.vue";
|
|
|
+import LoginStepOnePanel from "src/components/login/LoginStepOnePanel.vue";
|
|
|
+import LoginStepThreePanel from "src/components/login/LoginStepThreePanel.vue";
|
|
|
+import LoginStepTwoPanel from "src/components/login/LoginStepTwoPanel.vue";
|
|
|
|
|
|
-const router = useRouter();
|
|
|
const { setAuthDataFromPayload } = useAuth();
|
|
|
const flowStore = useRegistrationFlowStore();
|
|
|
+const router = useRouter();
|
|
|
|
|
|
-const email = ref('');
|
|
|
-const phone = ref('');
|
|
|
-const code = ref('');
|
|
|
+const clicked = ref(false);
|
|
|
+const code = ref("");
|
|
|
+const email = ref("");
|
|
|
+const isLogin = ref(false);
|
|
|
|
|
|
-const stepThreeForm = ref({
|
|
|
- name: '',
|
|
|
- document: '',
|
|
|
- zip_code: '',
|
|
|
- address: '',
|
|
|
- number: '',
|
|
|
- district: '',
|
|
|
- complement: '',
|
|
|
- nickname: '',
|
|
|
- instructions: '',
|
|
|
- address_type: 'home',
|
|
|
- no_complement: false,
|
|
|
- city: '',
|
|
|
- state: '',
|
|
|
-});
|
|
|
+const loginForm = ref(null);
|
|
|
|
|
|
-const steps = ref(1); // 1 = credentials | 2 = code | 3 = user fields | 4 = cep only
|
|
|
-const clicked = ref(false);
|
|
|
-const submitting = ref(false);
|
|
|
+const phone = ref("");
|
|
|
|
|
|
-onMounted(() => {
|
|
|
- setTimeout(() => {
|
|
|
- clicked.value = true;
|
|
|
- }, 1500);
|
|
|
+const stepAvatarForm = ref({
|
|
|
+ avatar: null,
|
|
|
});
|
|
|
-const loginForm = ref(null);
|
|
|
-const isLogin = ref(false);
|
|
|
|
|
|
-const sendValidationCode = async () => {
|
|
|
- const response = await sendCode(email.value, phone.value);
|
|
|
- if (response.status === 201) {
|
|
|
- steps.value = 2;
|
|
|
- } else {
|
|
|
- console.error('Failed to send validation code');
|
|
|
- }
|
|
|
- return response;
|
|
|
-};
|
|
|
+const steps = ref(1);
|
|
|
|
|
|
-const validateCodeInput = async () => {
|
|
|
- const response = await validateCode(email.value, phone.value, code.value, isLogin.value);
|
|
|
- if (response.status === 200) {
|
|
|
- if(isLogin.value == true) {
|
|
|
- await setAuthDataFromPayload(response.data.payload);
|
|
|
- router.push({ name: 'DashboardPage' });
|
|
|
- } else {
|
|
|
- steps.value = 3;
|
|
|
- }
|
|
|
- } else {
|
|
|
- console.error('Invalid validation code');
|
|
|
- }
|
|
|
-};
|
|
|
+const stepThreeForm = ref({
|
|
|
+ address: "",
|
|
|
+ address_type: "home",
|
|
|
+ city: "",
|
|
|
+ complement: "",
|
|
|
+ district: "",
|
|
|
+ document: "",
|
|
|
+ instructions: "",
|
|
|
+ name: "",
|
|
|
+ nickname: "",
|
|
|
+ no_complement: false,
|
|
|
+ number: "",
|
|
|
+ state: "",
|
|
|
+ zip_code: "",
|
|
|
+});
|
|
|
|
|
|
-const registerUserAndClient = async () => {
|
|
|
- const payload = {
|
|
|
- ...stepThreeForm.value,
|
|
|
- email: email.value,
|
|
|
- phone: phone.value,
|
|
|
- code: code.value,
|
|
|
- has_complement: !stepThreeForm.value.no_complement,
|
|
|
- };
|
|
|
- // delete payload.no_complement;
|
|
|
+const submitting = ref(false);
|
|
|
|
|
|
- const response = await createUserAndClient(payload);
|
|
|
- if (response.status === 200) {
|
|
|
- await setAuthDataFromPayload(response.data.payload);
|
|
|
- router.push({ name: 'DashboardPage' });
|
|
|
- } else {
|
|
|
- console.error('Failed to create user and client');
|
|
|
+const goBack = () => {
|
|
|
+ if (steps.value === 4) {
|
|
|
+ steps.value = 3;
|
|
|
+ } else if (steps.value === 5) {
|
|
|
+ steps.value = 4;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
const navigateToMap = (lat, lng) => {
|
|
|
flowStore.setCredentials(email.value, phone.value, code.value);
|
|
|
flowStore.setInitialLocation(lat, lng);
|
|
|
- router.push({ name: 'LocationMapPage' });
|
|
|
+ router.push({ name: "LocationMapPage" });
|
|
|
};
|
|
|
|
|
|
const onCepResolved = (geoData) => {
|
|
|
@@ -190,30 +222,135 @@ const onDeviceLocation = ({ lat, lng }) => {
|
|
|
|
|
|
const onSubmit = async () => {
|
|
|
submitting.value = true;
|
|
|
+
|
|
|
try {
|
|
|
switch (steps.value) {
|
|
|
case 1: {
|
|
|
const response = await sendValidationCode();
|
|
|
+
|
|
|
isLogin.value = response.data.payload.isLogin;
|
|
|
break;
|
|
|
}
|
|
|
- case 2: await validateCodeInput(); break;
|
|
|
- case 3: await registerUserAndClient(); break;
|
|
|
- default: break;
|
|
|
+
|
|
|
+ case 2:
|
|
|
+ await validateCodeInput();
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3:
|
|
|
+ steps.value = 4;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 4:
|
|
|
+ await registerUserAndClient();
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ break;
|
|
|
}
|
|
|
} finally {
|
|
|
submitting.value = false;
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
+const registerUserAndClient = async () => {
|
|
|
+ const payload = new FormData();
|
|
|
+
|
|
|
+ const append = (key, value) => {
|
|
|
+ if (value === null || value === undefined || value === "") {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (typeof value === "boolean") {
|
|
|
+ payload.append(key, value ? "1" : "0");
|
|
|
+ } else {
|
|
|
+ payload.append(key, value);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ Object.entries(stepThreeForm.value).forEach(([key, value]) => {
|
|
|
+ if (key === "no_complement") {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (key === "complement" && stepThreeForm.value.no_complement) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ append(key, value);
|
|
|
+ });
|
|
|
+
|
|
|
+ append("avatar", stepAvatarForm.value.avatar);
|
|
|
+ append("code", code.value);
|
|
|
+ append("email", email.value);
|
|
|
+ append("has_complement", !stepThreeForm.value.no_complement);
|
|
|
+ append("phone", phone.value);
|
|
|
+
|
|
|
+ const response = await createUserAndClient(payload);
|
|
|
+
|
|
|
+ if (response.status === 200) {
|
|
|
+ await setAuthDataFromPayload(response.data.payload);
|
|
|
+ router.push({ name: "DashboardPage" });
|
|
|
+ } else {
|
|
|
+ console.error("Failed to create user and client");
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const sendValidationCode = async () => {
|
|
|
+ const response = await sendCode(email.value, phone.value);
|
|
|
+
|
|
|
+ if (response.status === 201) {
|
|
|
+ steps.value = 2;
|
|
|
+ } else {
|
|
|
+ console.error("Failed to send validation code");
|
|
|
+ }
|
|
|
+
|
|
|
+ return response;
|
|
|
+};
|
|
|
+
|
|
|
+const validateCodeInput = async () => {
|
|
|
+ const response = await validateCode(
|
|
|
+ email.value,
|
|
|
+ phone.value,
|
|
|
+ code.value,
|
|
|
+ isLogin.value,
|
|
|
+ );
|
|
|
+
|
|
|
+ if (response.status === 200) {
|
|
|
+ if (isLogin.value === true) {
|
|
|
+ await setAuthDataFromPayload(response.data.payload);
|
|
|
+ router.push({ name: "DashboardPage" });
|
|
|
+ } else {
|
|
|
+ steps.value = 3;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.error("Invalid validation code");
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ setTimeout(() => {
|
|
|
+ clicked.value = true;
|
|
|
+ }, 1500);
|
|
|
+});
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
.fade-slide-enter-active,
|
|
|
.fade-slide-leave-active {
|
|
|
- transition: opacity 0.35s ease, transform 0.35s ease;
|
|
|
+ transition:
|
|
|
+ opacity 0.35s ease,
|
|
|
+ transform 0.35s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.fade-slide-enter-from {
|
|
|
+ opacity: 0;
|
|
|
+ transform: translateY(6px);
|
|
|
+}
|
|
|
+
|
|
|
+.fade-slide-leave-to {
|
|
|
+ opacity: 0;
|
|
|
+ transform: translateY(-6px);
|
|
|
}
|
|
|
-.fade-slide-enter-from { opacity: 0; transform: translateY(6px); }
|
|
|
-.fade-slide-leave-to { opacity: 0; transform: translateY(-6px); }
|
|
|
|
|
|
.login-page {
|
|
|
min-height: 100vh;
|
|
|
@@ -290,7 +427,6 @@ const onSubmit = async () => {
|
|
|
min-height: 36px;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- justify-content: flex-end;
|
|
|
}
|
|
|
|
|
|
.flow-logo {
|
|
|
@@ -318,4 +454,4 @@ const onSubmit = async () => {
|
|
|
.flow-footer {
|
|
|
padding: 20px 0 calc(12px + env(safe-area-inset-bottom));
|
|
|
}
|
|
|
-</style>
|
|
|
+</style>
|