broker_ demo

This commit is contained in:
saparatayev 2023-03-23 12:02:07 +05:00
parent 413c17e489
commit 628c50ad98
4 changed files with 399 additions and 0 deletions

View File

@ -21,6 +21,11 @@ const routes = [
name: "documents",
component: () => import("../views/document/Main.vue"),
},
{
path: "broker-application",
name: "broker-applications",
component: () => import("../views/broker/Main.vue"),
},
{
path: "ticket-list",
name: "ticket-list",

83
src/stores/broker.js Normal file
View File

@ -0,0 +1,83 @@
import { defineStore } from "pinia";
import { fetchWrapper } from "@/api";
import { useAlertStore } from "@/stores";
// import { useAuthStore } from "@/stores";
// const authStore = useAuthStore();
// const { user } = storeToRefs(authStore);
const baseUrl = `${import.meta.env.VITE_API_URL}/api/broker-application`;
export const useBrokerStore = defineStore({
id: "broker",
state: () => ({
brokerApplication: null,
}),
actions: {
async getApplication() {
try {
const response = await fetchWrapper.get(`${baseUrl}`);
// update pinia state
this.application = response["data"];
} catch (error) {
// const alertStore = useAlertStore();
// alertStore.error(error);
}
},
async fileUpload(attachmentId, docFile) {
try {
let formData = new FormData();
formData.append("file", docFile);
const response = await fetchWrapper.post(
`${baseUrl}/upload/${attachmentId}`,
formData,
true
);
// update pinia state
await this.getApplication();
const alertStore = useAlertStore();
// trigger alert
alertStore.success('Successfully uploaded');
} catch (error) {
// const alertStore = useAlertStore();
// alertStore.error(error);
}
},
async apply() {
try {
const response = await fetchWrapper.post(`${baseUrl}/apply`);
if(response != undefined) {
// update pinia state
await this.getApplication();
const alertStore = useAlertStore();
// trigger alert
alertStore.success('Successfully applied');
}
} catch (error) {
// const alertStore = useAlertStore();
// alertStore.error(error);
}
},
// async downloadQuestionnaire(token) {
// try {
// await fetchWrapper.get(`http://ba.digital-tps.tk/export-questionnaire/${token}`);
// } catch (error) {
// // const alertStore = useAlertStore();
// // alertStore.error(error);
// }
// },
},
});

View File

@ -4,3 +4,4 @@ export * from "./countries";
export * from "./categories";
export * from "./application";
export * from "./tickets";
export * from "./broker";

310
src/views/broker/Main.vue Normal file
View File

@ -0,0 +1,310 @@
<template>
<div class="grid grid-cols-1 lg:grid-cols-4 gap-x-0 lg:gap-x-6 mt-5 pb-20">
<div class="intro-y col-span-1">
<div class="intro-y flex items-center my-8">
<h2 class="text-lg font-medium mr-auto">{{ $t("DOCUMENTS") }}</h2>
</div>
<h4 class="text-md font-medium mr-auto pb-2">
{{ $t("PLEASE_UPLOAD_DOCUMENTS") }}
</h4>
<div class="pb-6 text-primary">
<!-- <i18n-t keypath="APPLICATION_PROCESS_DESCRIPTION" for="QUESTIONNAIRE_LINK">
<a @click.prevent="downloadQuestionnaire" href="#" class="text-primary font-bold">{{ $t('QUESTIONNAIRE_LINK') }}</a>
</i18n-t> -->
{{ $t("APPLICATION_PROCESS_DESCRIPTION") }}
</div>
<!-- BEGIN: Files -->
<div class="grid grid-cols-2 lg:grid-cols-1 xl:grid-cols-2 gap-3 mt-5">
<div
class="intro-y"
>
<div
class="file box rounded-md px-5 pt-8 pb-5 px-3 sm:px-5 relative zoom-in"
>
<a
:href="baseUrl + QUESTIONNAIRE_LINK"
class="w-3/5 file__icon file__icon--file mx-auto"
@click.prevent="downloadQuestionnaire"
>
<div class="file__icon__file-name">
{{ EXTENSION_QUESTIONNAIRE_FILE }}
</div>
</a>
<a
:href="baseUrl + QUESTIONNAIRE_LINK"
class="block font-medium mt-4 text-center truncate"
@click.prevent="downloadQuestionnaire"
>
{{ $t("NAME_QUESTIONNAIRE_FILE") }}.{{ EXTENSION_QUESTIONNAIRE_FILE.toLowerCase() }}
</a>
</div>
</div>
<div
class="intro-y"
>
<div
class="file box rounded-md px-5 pt-8 pb-5 px-3 sm:px-5 relative zoom-in"
>
<a :href="baseUrl + LETTER_LINK + accountType + '.' + EXTENSION_LETTER_FILE.toLowerCase()" class="w-3/5 file__icon file__icon--file mx-auto">
<div class="file__icon__file-name">
{{ EXTENSION_LETTER_FILE }}
</div>
</a>
<a :href="baseUrl + LETTER_LINK + accountType + '.' + EXTENSION_LETTER_FILE.toLowerCase()" class="block font-medium mt-4 text-center truncate">
{{ $t("NAME_LETTER_FILE") }}.{{ EXTENSION_LETTER_FILE.toLowerCase() }}
</a>
</div>
</div>
</div>
<!-- END: Files -->
</div>
<div class="intro-y col-span-3">
<!-- BEGIN: Upload -->
<div class="intro-y flex items-center my-8">
<h2 class="text-lg font-medium mr-auto">{{ $t("DOCUMENTS_TWO") }}</h2>
</div>
<h4 v-html="$t('PLEASE_UPLOAD_DOCUMENTS_TWO')" class="text-md font-medium mr-auto pb-2"></h4>
<div class="pb-6 text-primary">
{{ $t("APPLICATION_PROCESS_DESCRIPTION_TWO") }}
</div>
<div class="intro-y box p-5 mt-5" v-if="application">
<div
class="border border-slate-200/60 dark:border-darkmode-400 rounded-md p-5 divide-y md:divide-y-0"
>
<!-- <template v-if="application"> -->
<!-- BEGIN 1.row -->
<div
class="flex flex-wrap md:flex-nowrap items-center pt-2"
v-for="(attachment, index) in application.attachments"
:key="attachment.id"
>
<div class="flex items-center self-end my-2 md:my-0 w-[55px]">
<Tippy
class="grow-0 mr-5"
style="padding: 3px"
:content="attachment.document_description"
>
<InfoIcon class="w-7 h-7 rounded-full text-white bg-primary" />
</Tippy>
</div>
<div class="grow text-md font-medium mr-5 self-center w-[calc(100%_-_75px)]">
<a :class="{'text-primary': attachment.attachment_file_path}" :href="attachment.attachment_file_path ? baseUrl + attachment.attachment_file_path : 'javascript:;'">{{ index + 1 }}. {{ attachment.attachment_name }}</a>
<p v-if="validationError[index]" class="text-danger">{{ validationError[index] }}</p>
</div>
<div class="flex items-center self-end my-2 md:my-0 w-full md:w-auto justify-end md:justify-start">
<label
class="grow-0 btn mr-5"
style="padding: 3px"
:class="{'opacity-30': application.state === APPLICATION_APPROVED_STATE || application.state === APPLICATION_ACCEPTED_STATE, 'btn-outline-primary': !isLoadingDoc[index]}"
>
<input type="file"
@change="onFileChange(index, attachment, $event)"
class="hidden"
:disabled="application.state === APPLICATION_APPROVED_STATE || application.state === APPLICATION_ACCEPTED_STATE"
/>
<LoadingIcon class="w-7 h-7" icon="oval" color="#003197" v-if="isLoadingDoc[index]" />
<UploadIcon class="w-7 h-7" v-else />
</label>
<div class="grow-0">
<CheckCircleIcon class="w-7 h-7 text-success" :class="{'text-danger': !attachment.attachment_size}" />
</div>
</div>
</div>
<!-- END: 1.row -->
<!-- </template> -->
</div>
<Alert
class="font-medium alert-secondary mt-4"
v-if="application.state === APPLICATION_REFINE_STATE"
>
{{ $t('APPLICATION_NEEDS_TO_BE_IMPROVED_TEXT_INTRO') }} <br>
<template v-if="application.refine_note">
{{ $t('REFINE_NOTE') }}: {{ application.refine_note }}
</template>
<br>
<i18n-t
v-if="application.ticket"
keypath="APPLICATION_NEEDS_TO_BE_IMPROVED_TEXT"
for="APPLICATION_NEEDS_TO_BE_IMPROVED_LINK"
>
<a
@click.prevent="goToTicket(application.ticket.id)"
href="#"
class="font-bold underline"
>
{{ $t('APPLICATION_NEEDS_TO_BE_IMPROVED_LINK') }}
</a>
</i18n-t>
</Alert>
<Alert
class="font-medium mt-4 alert-primary"
v-if="application.state === APPLICATION_ACCEPTED_STATE"
>
{{ $t('APPLICATION_ACCEPTED_BY', {accepted_by: application.accepted_by}) }}
<br>
{{ $t('APPLICATION_ACCEPTED_DATE', {accepted_date: normalizeDate(application.accepted_date)}) }}
</Alert>
<Alert
class="font-medium text-white mt-4 alert-success"
v-if="application.state === APPLICATION_APPROVED_STATE"
>
{{ $t('APPLICATION_APPROVED_BY', {approved_by: application.approved_by}) }}
<br>
{{ $t('APPLICATION_APPROVED_DATE', {approved_date: application.approved_date}) }}
</Alert>
<Alert
class="font-medium alert-warning mt-4"
v-if="application.state === APPLICATION_NEW_STATE"
>
{{ $t('APPLICATION_APPLIED') }}
</Alert>
<div
class="flex justify-end mt-4"
v-if="application.state === APPLICATION_NEW_STATE || application.state === APPLICATION_REFINE_STATE || application.state === APPLICATION_DRAFT_STATE"
>
<button class="btn btn-primary" @click="apply" :disabled="isApplying">
{{ $t("APPLY") }}
<LoadingIcon
icon="oval"
color="white"
class="w-4 h-4 ml-2"
v-if="isApplying"
/>
</button>
</div>
</div>
<!-- END: Upload -->
</div>
</div>
</template>
<script setup>
import { onBeforeMount, watch, ref } from "vue";
import { useBrokerStore } from '@/stores';
import { storeToRefs } from 'pinia';
import {
BYTES_IN_KB,
ALLOWED_FILE_TYPES,
QUESTIONNAIRE_LINK,
LETTER_LINK,
APPLICATION_DRAFT_STATE,
APPLICATION_NEW_STATE,
APPLICATION_ACCEPTED_STATE,
APPLICATION_REFINE_STATE,
APPLICATION_APPROVED_STATE,
EXTENSION_LETTER_FILE,
EXTENSION_QUESTIONNAIRE_FILE,
normalizeDate
} from "@/helpers";
import i18nn from "@/i18n";
import { useAuthStore } from "@/stores";
import router from "@/router";
const baseUrl = `${import.meta.env.VITE_API_URL}`;
const authStore = useAuthStore();
const { user } = storeToRefs(authStore);
const accountType = ref("");
const brokerStore = useBrokerStore();
const { application } = storeToRefs(brokerStore);
const docFile = ref(null);
const validationError = ref({});
const isLoadingDoc = ref({});
const isApplying = ref(false);
const onFileChange = async (index, attachment, e) => {
isLoadingDoc.value = {};
isLoadingDoc.value[index] = true;
let files = e.target.files || e.dataTransfer.files
if (!files.length) {
docFile.value = null;
return
}
docFile.value = files[0]
if(fileIsValid(index, attachment)) {
await brokerStore.fileUpload(attachment.attachment_id, files[0]);
}
isLoadingDoc.value[index] = false;
}
const fileIsValid = (index, attachment) => {
validationError.value = {};
if(docFile.value.size > attachment.document_max_size * BYTES_IN_KB) {
validationError.value[index] = i18nn.global.t('FILE_MAX_SIZE', {size: attachment.document_max_size});
return false;
}
if(ALLOWED_FILE_TYPES.indexOf(docFile.value.type) < 0) {
validationError.value[index] = i18nn.global.t('FILE_ALLOWED_TYPES', {file_types: ALLOWED_FILE_TYPES.join(', ')});
return false;
}
return true;
};
const checkRequiredFilesUploaded = () => {
validationError.value = {};
let validToContinueRequest = true;
application.value.attachments.forEach((element, index) => {
if(element.is_required && !element.attachment_file_path) {
validationError.value[index] = i18nn.global.t('REQUIRED_VALIDATION');
validToContinueRequest = false;
}
});
return validToContinueRequest;
};
const apply = async () => {
if(checkRequiredFilesUploaded()) {
isApplying.value = true;
await brokerStore.apply();
isApplying.value = false;
}
};
const goToTicket = (ticketId) => {
router.push({ name: "ticket-list", query: { ticketId: ticketId } });
};
const downloadQuestionnaire = async () => {
// console.log(user.value.token);
window.open(baseUrl + QUESTIONNAIRE_LINK + user.value.token, '_blank');
// await brokerStore.downloadQuestionnaire(user.value.token);
};
onBeforeMount(async () => {
await brokerStore.getApplication();
if(!application.value) {
router.push({ name: "error-page" });
}
console.log(application.value);
accountType.value = localStorage.getItem('account_type');
});
</script>