|
@@ -60,89 +60,6 @@
|
|
|
</template>
|
|
</template>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div class="column items-center q-gutter-y-sm">
|
|
|
|
|
- <div
|
|
|
|
|
- :ref="fieldRefs.document_front"
|
|
|
|
|
- class="cursor-pointer"
|
|
|
|
|
- @click="openDocSubStep"
|
|
|
|
|
- >
|
|
|
|
|
- <div
|
|
|
|
|
- v-if="docDone"
|
|
|
|
|
- class="row items-center justify-center q-gutter-x-sm"
|
|
|
|
|
- >
|
|
|
|
|
- <div class="photo-circle photo-circle--small photo-circle--done">
|
|
|
|
|
- <img
|
|
|
|
|
- v-if="documentFrontPreviewUrl"
|
|
|
|
|
- class="photo-circle__thumb"
|
|
|
|
|
- :src="documentFrontPreviewUrl"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="photo-circle photo-circle--small photo-circle--done">
|
|
|
|
|
- <img
|
|
|
|
|
- v-if="documentBackPreviewUrl"
|
|
|
|
|
- class="photo-circle__thumb"
|
|
|
|
|
- :src="documentBackPreviewUrl"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div
|
|
|
|
|
- v-else
|
|
|
|
|
- class="photo-circle photo-circle--pending"
|
|
|
|
|
- >
|
|
|
|
|
- <q-icon
|
|
|
|
|
- color="white"
|
|
|
|
|
- name="mdi-card-account-details-outline"
|
|
|
|
|
- size="52px"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div
|
|
|
|
|
- v-if="serverErrors.document_front"
|
|
|
|
|
- class="text-negative font12 text-center"
|
|
|
|
|
- >
|
|
|
|
|
- {{ serverErrors.document_front }}
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div
|
|
|
|
|
- v-if="serverErrors.document_back"
|
|
|
|
|
- :ref="fieldRefs.document_back"
|
|
|
|
|
- class="text-negative font12 text-center"
|
|
|
|
|
- >
|
|
|
|
|
- {{ serverErrors.document_back }}
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <template v-if="!docDone">
|
|
|
|
|
- <q-btn
|
|
|
|
|
- color="primary-button"
|
|
|
|
|
- no-caps
|
|
|
|
|
- padding="10px 28px"
|
|
|
|
|
- rounded
|
|
|
|
|
- :label="t('provider.login.steps.step_4.btn_document')"
|
|
|
|
|
- @click="openDocSubStep"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <div class="font12 text-center text-text">
|
|
|
|
|
- {{ t('provider.login.steps.step_4.document_hint') }}
|
|
|
|
|
- </div>
|
|
|
|
|
- </template>
|
|
|
|
|
-
|
|
|
|
|
- <template v-else>
|
|
|
|
|
- <div class="items-center q-gutter-x-xs row">
|
|
|
|
|
- <q-icon
|
|
|
|
|
- color="positive"
|
|
|
|
|
- name="check_circle"
|
|
|
|
|
- size="18px"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <span class="text-primary">
|
|
|
|
|
- {{ t('provider.login.steps.step_4.document_sent') }}
|
|
|
|
|
- </span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </template>
|
|
|
|
|
- </div>
|
|
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<Teleport to="body">
|
|
<Teleport to="body">
|
|
@@ -203,168 +120,6 @@
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</Teleport>
|
|
</Teleport>
|
|
|
-
|
|
|
|
|
- <Teleport to="body">
|
|
|
|
|
- <div
|
|
|
|
|
- v-if="showDocSubStep"
|
|
|
|
|
- class="fs-overlay doc-substep"
|
|
|
|
|
- >
|
|
|
|
|
- <div class="doc-substep__header">
|
|
|
|
|
- <q-btn
|
|
|
|
|
- flat
|
|
|
|
|
- icon="arrow_back"
|
|
|
|
|
- round
|
|
|
|
|
- @click="closeDocSubStep"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="doc-substep__body column items-center q-gutter-y-lg">
|
|
|
|
|
- <div class="doc-slot column items-center q-gutter-y-sm">
|
|
|
|
|
- <div class="text-primary">
|
|
|
|
|
- {{ t('provider.login.steps.step_4.document_front') }}
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="font12 text-center text-text">
|
|
|
|
|
- {{ t('provider.login.steps.step_4.document_front_desc') }}
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div
|
|
|
|
|
- class="doc-slot__preview"
|
|
|
|
|
- :class="docFrontDraft ? 'doc-slot__preview--done' : 'doc-slot__preview--pending'"
|
|
|
|
|
- >
|
|
|
|
|
- <q-img
|
|
|
|
|
- v-if="docFrontDraft"
|
|
|
|
|
- class="doc-slot__thumb"
|
|
|
|
|
- :src="docFrontPreviewUrl"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <q-icon
|
|
|
|
|
- v-else
|
|
|
|
|
- color="white"
|
|
|
|
|
- name="mdi-card-account-details-outline"
|
|
|
|
|
- size="48px"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div
|
|
|
|
|
- v-if="docFrontDraft"
|
|
|
|
|
- class="items-center q-gutter-x-xs row"
|
|
|
|
|
- >
|
|
|
|
|
- <q-icon
|
|
|
|
|
- color="positive"
|
|
|
|
|
- name="check_circle"
|
|
|
|
|
- size="16px"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <span class="font12 text-primary">
|
|
|
|
|
- {{ t('provider.login.steps.step_4.photo_captured') }}
|
|
|
|
|
- </span>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div
|
|
|
|
|
- v-if="docFrontError"
|
|
|
|
|
- class="text-negative font12 text-center"
|
|
|
|
|
- >
|
|
|
|
|
- {{ t('provider.login.steps.step_4.error_message') }}
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <q-btn
|
|
|
|
|
- color="primary-button"
|
|
|
|
|
- no-caps
|
|
|
|
|
- padding="8px 22px"
|
|
|
|
|
- rounded
|
|
|
|
|
- :label="docFrontDraft
|
|
|
|
|
- ? t('provider.login.steps.step_4.btn_retake')
|
|
|
|
|
- : t('provider.login.steps.step_4.btn_capture_front')"
|
|
|
|
|
- :loading="loadingDocFront"
|
|
|
|
|
- @click="captureDocFront"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="doc-slot column items-center q-gutter-y-sm">
|
|
|
|
|
- <div class="text-primary">
|
|
|
|
|
- {{ t('provider.login.steps.step_4.document_back') }}
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="font12 text-center text-text">
|
|
|
|
|
- {{ t('provider.login.steps.step_4.document_back_desc') }}
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div
|
|
|
|
|
- class="doc-slot__preview"
|
|
|
|
|
- :class="docBackDraft ? 'doc-slot__preview--done' : 'doc-slot__preview--pending'"
|
|
|
|
|
- >
|
|
|
|
|
- <q-img
|
|
|
|
|
- v-if="docBackDraft"
|
|
|
|
|
- class="doc-slot__thumb"
|
|
|
|
|
- :src="docBackPreviewUrl"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <q-icon
|
|
|
|
|
- v-else
|
|
|
|
|
- color="white"
|
|
|
|
|
- name="mdi-card-account-details-outline"
|
|
|
|
|
- size="48px"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div
|
|
|
|
|
- v-if="docBackDraft"
|
|
|
|
|
- class="items-center q-gutter-x-xs row"
|
|
|
|
|
- >
|
|
|
|
|
- <q-icon
|
|
|
|
|
- color="positive"
|
|
|
|
|
- name="check_circle"
|
|
|
|
|
- size="16px"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <span class="font12 text-primary">
|
|
|
|
|
- {{ t('provider.login.steps.step_4.photo_captured') }}
|
|
|
|
|
- </span>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div
|
|
|
|
|
- v-if="docBackError"
|
|
|
|
|
- class="text-negative font12 text-center"
|
|
|
|
|
- >
|
|
|
|
|
- {{ t('provider.login.steps.step_4.error_message') }}
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <q-btn
|
|
|
|
|
- color="primary-button"
|
|
|
|
|
- no-caps
|
|
|
|
|
- padding="8px 22px"
|
|
|
|
|
- rounded
|
|
|
|
|
- :label="docBackDraft
|
|
|
|
|
- ? t('provider.login.steps.step_4.btn_retake')
|
|
|
|
|
- : t('provider.login.steps.step_4.btn_capture_back')"
|
|
|
|
|
- :loading="loadingDocBack"
|
|
|
|
|
- @click="captureDocBack"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="doc-substep__footer">
|
|
|
|
|
- <q-btn
|
|
|
|
|
- v-if="docSubStepDone"
|
|
|
|
|
- color="primary-button"
|
|
|
|
|
- no-caps
|
|
|
|
|
- padding="14px 48px"
|
|
|
|
|
- rounded
|
|
|
|
|
- style="min-width: 200px"
|
|
|
|
|
- :label="t('provider.login.steps.step_4.btn_continue')"
|
|
|
|
|
- @click="confirmDocCapture"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <div
|
|
|
|
|
- v-else
|
|
|
|
|
- class="font12 text-center text-grey-6"
|
|
|
|
|
- >
|
|
|
|
|
- {{ t('provider.login.steps.step_4.upload_all_photos') }}
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </Teleport>
|
|
|
|
|
</q-card-section>
|
|
</q-card-section>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -395,8 +150,6 @@ const serverErrors = inject("serverErrors", ref({}));
|
|
|
|
|
|
|
|
const fieldRefs = {
|
|
const fieldRefs = {
|
|
|
selfie: ref(null),
|
|
selfie: ref(null),
|
|
|
- document_front: ref(null),
|
|
|
|
|
- document_back: ref(null),
|
|
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
defineExpose({
|
|
defineExpose({
|
|
@@ -409,29 +162,7 @@ const resultIcon = ref('photo_camera');
|
|
|
const resultMessage = ref('');
|
|
const resultMessage = ref('');
|
|
|
const showResult = ref(false);
|
|
const showResult = ref(false);
|
|
|
|
|
|
|
|
-const showDocSubStep = ref(false);
|
|
|
|
|
-const docFrontDraft = ref(null);
|
|
|
|
|
-const docBackDraft = ref(null);
|
|
|
|
|
-const docFrontPreviewUrl = ref(null);
|
|
|
|
|
-const docBackPreviewUrl = ref(null);
|
|
|
|
|
-const loadingDocFront = ref(false);
|
|
|
|
|
-const loadingDocBack = ref(false);
|
|
|
|
|
-const docFrontError = ref(false);
|
|
|
|
|
-const docBackError = ref(false);
|
|
|
|
|
-
|
|
|
|
|
const selfiePreviewUrl = ref(null);
|
|
const selfiePreviewUrl = ref(null);
|
|
|
-const documentFrontPreviewUrl = ref(null);
|
|
|
|
|
-const documentBackPreviewUrl = ref(null);
|
|
|
|
|
-
|
|
|
|
|
-const docDone = computed(() => (
|
|
|
|
|
- !!form.value.document_back
|
|
|
|
|
- && !!form.value.document_front
|
|
|
|
|
-));
|
|
|
|
|
-
|
|
|
|
|
-const docSubStepDone = computed(() => (
|
|
|
|
|
- !!docFrontDraft.value
|
|
|
|
|
- && !!docBackDraft.value
|
|
|
|
|
-));
|
|
|
|
|
|
|
|
|
|
const selfieDone = computed(() => !!form.value.selfie);
|
|
const selfieDone = computed(() => !!form.value.selfie);
|
|
|
|
|
|
|
@@ -444,8 +175,6 @@ const syncPreviewUrl = (previewRef, file) => {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
watch(() => form.value.selfie, (file) => syncPreviewUrl(selfiePreviewUrl, file), { immediate: true });
|
|
watch(() => form.value.selfie, (file) => syncPreviewUrl(selfiePreviewUrl, file), { immediate: true });
|
|
|
-watch(() => form.value.document_front, (file) => syncPreviewUrl(documentFrontPreviewUrl, file), { immediate: true });
|
|
|
|
|
-watch(() => form.value.document_back, (file) => syncPreviewUrl(documentBackPreviewUrl, file), { immediate: true });
|
|
|
|
|
|
|
|
|
|
const base64ToFile = (base64, filename, mimeType = 'image/jpeg') => {
|
|
const base64ToFile = (base64, filename, mimeType = 'image/jpeg') => {
|
|
|
const byteString = atob(base64);
|
|
const byteString = atob(base64);
|
|
@@ -471,12 +200,10 @@ const closeResult = () => {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-const openCamera = async (direction) => {
|
|
|
|
|
|
|
+const openCamera = async () => {
|
|
|
const photo = await Camera.getPhoto({
|
|
const photo = await Camera.getPhoto({
|
|
|
allowEditing: false,
|
|
allowEditing: false,
|
|
|
- direction: direction === 'front'
|
|
|
|
|
- ? CameraDirection.Front
|
|
|
|
|
- : CameraDirection.Rear,
|
|
|
|
|
|
|
+ direction: CameraDirection.Front,
|
|
|
quality: 85,
|
|
quality: 85,
|
|
|
resultType: CameraResultType.Base64,
|
|
resultType: CameraResultType.Base64,
|
|
|
saveToGallery: false,
|
|
saveToGallery: false,
|
|
@@ -490,93 +217,10 @@ const openCamera = async (direction) => {
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-const setDraftFile = (side, file) => {
|
|
|
|
|
- const draftRef = side === 'front' ? docFrontDraft : docBackDraft;
|
|
|
|
|
- const previewRef = side === 'front' ? docFrontPreviewUrl : docBackPreviewUrl;
|
|
|
|
|
-
|
|
|
|
|
- draftRef.value = file;
|
|
|
|
|
- syncPreviewUrl(previewRef, file);
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-const captureDocSide = async (side) => {
|
|
|
|
|
- const loadingRef = side === 'front' ? loadingDocFront : loadingDocBack;
|
|
|
|
|
- const errorRef = side === 'front' ? docFrontError : docBackError;
|
|
|
|
|
-
|
|
|
|
|
- if (loadingRef.value) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- loadingRef.value = true;
|
|
|
|
|
- errorRef.value = false;
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- const file = await openCamera('rear');
|
|
|
|
|
-
|
|
|
|
|
- setDraftFile(side, file);
|
|
|
|
|
- } catch (err) {
|
|
|
|
|
- const msg = (err?.message || '').toLowerCase();
|
|
|
|
|
-
|
|
|
|
|
- if (
|
|
|
|
|
- !msg.includes('cancel')
|
|
|
|
|
- && !msg.includes('dismiss')
|
|
|
|
|
- && !msg.includes('no image')
|
|
|
|
|
- ) {
|
|
|
|
|
- errorRef.value = true;
|
|
|
|
|
- }
|
|
|
|
|
- } finally {
|
|
|
|
|
- loadingRef.value = false;
|
|
|
|
|
- }
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-const captureDocFront = () => captureDocSide('front');
|
|
|
|
|
-const captureDocBack = () => captureDocSide('back');
|
|
|
|
|
-
|
|
|
|
|
-const openDocSubStep = () => {
|
|
|
|
|
- if (!docFrontDraft.value && form.value.document_front) {
|
|
|
|
|
- setDraftFile('front', form.value.document_front);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!docBackDraft.value && form.value.document_back) {
|
|
|
|
|
- setDraftFile('back', form.value.document_back);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- docFrontError.value = false;
|
|
|
|
|
- docBackError.value = false;
|
|
|
|
|
- showDocSubStep.value = true;
|
|
|
|
|
-
|
|
|
|
|
- emit('update:show-sub-step', true);
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-const closeDocSubStep = () => {
|
|
|
|
|
- showDocSubStep.value = false;
|
|
|
|
|
-
|
|
|
|
|
- emit('update:show-sub-step', false);
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-const confirmDocCapture = () => {
|
|
|
|
|
- if (!docSubStepDone.value) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- form.value.document_front = docFrontDraft.value;
|
|
|
|
|
- form.value.document_back = docBackDraft.value;
|
|
|
|
|
- showDocSubStep.value = false;
|
|
|
|
|
-
|
|
|
|
|
- emit('update:show-sub-step', false);
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
onBeforeUnmount(() => {
|
|
onBeforeUnmount(() => {
|
|
|
- [
|
|
|
|
|
- docFrontPreviewUrl,
|
|
|
|
|
- docBackPreviewUrl,
|
|
|
|
|
- selfiePreviewUrl,
|
|
|
|
|
- documentFrontPreviewUrl,
|
|
|
|
|
- documentBackPreviewUrl,
|
|
|
|
|
- ].forEach((previewRef) => {
|
|
|
|
|
- if (previewRef.value) {
|
|
|
|
|
- URL.revokeObjectURL(previewRef.value);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ if (selfiePreviewUrl.value) {
|
|
|
|
|
+ URL.revokeObjectURL(selfiePreviewUrl.value);
|
|
|
|
|
+ }
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const takeSelfie = async () => {
|
|
const takeSelfie = async () => {
|
|
@@ -587,7 +231,7 @@ const takeSelfie = async () => {
|
|
|
loadingSelfie.value = true;
|
|
loadingSelfie.value = true;
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
- const file = await openCamera('front');
|
|
|
|
|
|
|
+ const file = await openCamera();
|
|
|
|
|
|
|
|
form.value.selfie = file;
|
|
form.value.selfie = file;
|
|
|
resultError.value = false;
|
|
resultError.value = false;
|
|
@@ -686,48 +330,4 @@ const takeSelfie = async () => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.doc-substep {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- flex-direction: column;
|
|
|
|
|
-
|
|
|
|
|
- &__header {
|
|
|
|
|
- padding: 12px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &__body {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- padding: 0 24px;
|
|
|
|
|
- overflow-y: auto;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &__footer {
|
|
|
|
|
- padding: 24px;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- flex-direction: column;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.doc-slot__preview {
|
|
|
|
|
- width: 160px;
|
|
|
|
|
- height: 110px;
|
|
|
|
|
- border-radius: 16px;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: center;
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
-
|
|
|
|
|
- &--pending {
|
|
|
|
|
- background-color: rgba(139, 92, 246, 0.18);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &--done {
|
|
|
|
|
- background: linear-gradient(-90deg, #ec48d1 5%, #6b11cb 65%, #2574fc 100%);
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.doc-slot__thumb {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
-}
|
|
|
|
|
</style>
|
|
</style>
|