AddEditProviderDialog.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. <template>
  2. <q-dialog ref="dialogRef" @hide="onDialogHide">
  3. <q-card class="q-dialog-plugin column full-width" style="width: 900px; max-width: 80vw;height: 90vh;">
  4. <DefaultDialogHeader :title="title" class="col-12" @close="onDialogCancel"/>
  5. <q-tabs v-model="tab" dense class="text-grey" active-color="primary" indicator-color="primary" align="justify">
  6. <q-tab name="data" label="Dados" />
  7. <q-tab v-if="provider" name="addresses" :label="$t('address.tab')" />
  8. <q-tab v-if="provider" name="payment_methods" :label="$t('provider_payment_methods.header')" />
  9. <q-tab v-if="provider" name="working_days" :label="$t('provider_working_days.header')" />
  10. <q-tab v-if="provider" name="blocked_days" :label="$t('provider_blocked_days.header')" />
  11. <q-tab v-if="provider" name="blocked_clients" :label="$t('provider_client_blocks.tab')" />
  12. <q-tab v-if="provider" name="sent_reviews" :label="$t('provider_reviews.sent_tab')" />
  13. <q-tab v-if="provider" name="received_reviews" :label="$t('provider_reviews.received_tab')" />
  14. </q-tabs>
  15. <q-separator v-if="provider" />
  16. <div class="col no-padding scroll">
  17. <q-tab-panels v-model="tab" animated>
  18. <q-tab-panel name="data">
  19. <q-form ref="formRef" @submit="onOKClick">
  20. <q-card-section class="row q-col-gutter-sm no-padding scroll">
  21. <UserSelect
  22. v-model="selectedUser"
  23. :label="$t('common.terms.user')"
  24. :rules="[inputRules.required]"
  25. :error="!!serverErrors?.user_id"
  26. :error-message="serverErrors?.user_id"
  27. :initial-id="provider ? provider.user_id : null"
  28. class="col-md-6 col-12"
  29. />
  30. <q-input
  31. v-model="form.document"
  32. :mask="documentMask"
  33. fill-mask
  34. unmasked-value
  35. :label="$t('provider.fields.document')"
  36. :rules="[inputRules.required, validateDocument]"
  37. :error="!!serverErrors?.document"
  38. :error-message="serverErrors?.document"
  39. class="col-md-6 col-12"
  40. />
  41. <q-input
  42. v-model="form.rg"
  43. mask="##.###.###-#"
  44. fill-mask
  45. :label="$t('provider.fields.rg')"
  46. :error="!!serverErrors?.rg"
  47. :error-message="serverErrors?.rg"
  48. class="col-md-6 col-12"
  49. />
  50. <DefaultInputDatePicker
  51. v-model:untreated-date="form.birth_date"
  52. :label="$t('provider.fields.birth_date')"
  53. :error="serverErrors?.birth_date"
  54. :error-message="serverErrors?.birth_date"
  55. class="col-md-6 col-12"
  56. />
  57. <DefaultCurrencyInput
  58. v-model="form.daily_price_8h"
  59. :label="$t('provider.fields.daily_price_8h')"
  60. :error="!!serverErrors?.daily_price_8h"
  61. :error-message="serverErrors?.daily_price_8h"
  62. :hint="$t('provider.hints.daily_price')"
  63. lazy-rules
  64. class="col-md-3 col-6"
  65. />
  66. <DefaultCurrencyInput
  67. v-model="form.daily_price_6h"
  68. :label="$t('provider.fields.daily_price_6h')"
  69. :error="!!serverErrors?.daily_price_6h"
  70. :error-message="serverErrors?.daily_price_6h"
  71. disable
  72. class="col-md-3 col-6"
  73. />
  74. <DefaultCurrencyInput
  75. v-model="form.daily_price_4h"
  76. :label="$t('provider.fields.daily_price_4h')"
  77. :error="!!serverErrors?.daily_price_4h"
  78. :error-message="serverErrors?.daily_price_4h"
  79. disable
  80. class="col-md-3 col-6"
  81. />
  82. <DefaultCurrencyInput
  83. v-model="form.daily_price_2h"
  84. :label="$t('provider.fields.daily_price_2h')"
  85. :error="!!serverErrors?.daily_price_2h"
  86. :error-message="serverErrors?.daily_price_2h"
  87. disable
  88. class="col-md-3 col-6"
  89. />
  90. <div class="col-12">
  91. <q-select
  92. v-model="form.approval_status"
  93. :options="approvalStatusOptions"
  94. :label="$t('provider.fields.approval_status')"
  95. emit-value
  96. map-options
  97. outlined
  98. dense
  99. :error="!!serverErrors?.approval_status"
  100. :error-message="serverErrors?.approval_status"
  101. class="col-12"
  102. />
  103. </div>
  104. <ProviderSpecialitiesPanel v-if="provider" :provider-id="provider.id" />
  105. <ProviderServicesTypesPanel v-if="provider" :provider-id="provider.id" />
  106. <div class="col-12 q-mt-md">
  107. <div class="row q-col-gutter-md">
  108. <div class="col-auto flex items-center">
  109. <q-avatar size="80px" color="grey-3">
  110. <q-icon name="mdi-account" size="50px" color="grey-6" />
  111. </q-avatar>
  112. </div>
  113. <div class="col row q-col-gutter-sm">
  114. <div class="col-md-6 col-12">
  115. <div class="text-subtitle2 text-grey-7">
  116. {{ $t('provider.fields.average_rating') }}
  117. </div>
  118. <div class="text-body1 text-weight-medium">
  119. {{ provider?.average_rating || '-' }}
  120. </div>
  121. </div>
  122. <div class="col-md-6 col-12">
  123. <div class="text-subtitle2 text-grey-7">
  124. {{ $t('provider.fields.total_services') }}
  125. </div>
  126. <div class="text-body1 text-weight-medium">
  127. {{ provider?.total_services || '0' }}
  128. </div>
  129. </div>
  130. <div class="col-md-6 col-12">
  131. <div class="text-subtitle2 text-grey-7 q-mb-sm">
  132. {{ $t('provider.fields.selfie_verified') }}
  133. </div>
  134. <q-checkbox
  135. v-model="form.selfie_verified"
  136. label="Verificar foto"
  137. color="primary"
  138. />
  139. </div>
  140. <div class="col-md-6 col-12">
  141. <div class="text-subtitle2 text-grey-7 q-mb-sm">
  142. {{ $t('provider.fields.document_verified') }}
  143. </div>
  144. <q-checkbox
  145. v-model="form.document_verified"
  146. label="Validar documentos"
  147. color="primary"
  148. />
  149. </div>
  150. </div>
  151. </div>
  152. </div>
  153. </q-card-section>
  154. <q-card-actions align="right">
  155. <q-btn
  156. :label="$t('common.actions.close')"
  157. flat
  158. color="primary"
  159. @click="onDialogCancel"
  160. />
  161. <q-btn
  162. color="secondary"
  163. :label="$t('common.actions.save')"
  164. type="submit"
  165. unelevated
  166. :loading="loading"
  167. :disable="!hasUpdatedFields"
  168. />
  169. </q-card-actions>
  170. </q-form>
  171. </q-tab-panel>
  172. <q-tab-panel v-if="provider" name="addresses">
  173. <AddressesPanel :source="'provider'" :source-id="provider.id" />
  174. </q-tab-panel>
  175. <q-tab-panel v-if="provider" name="payment_methods">
  176. <ProviderPaymentMethodsPanel :provider-id="provider.id" />
  177. </q-tab-panel>
  178. <q-tab-panel v-if="provider" name="working_days">
  179. <ProviderWorkingDaysPanel :provider-id="provider.id" />
  180. </q-tab-panel>
  181. <q-tab-panel v-if="provider" name="blocked_days">
  182. <ProviderBlockedDaysPanel :provider-id="provider.id" />
  183. </q-tab-panel>
  184. <q-tab-panel v-if="provider" name="blocked_clients">
  185. <ProviderClientsBlocksPanel :provider-id="provider.id" />
  186. </q-tab-panel>
  187. <q-tab-panel v-if="provider" name="sent_reviews">
  188. <ProviderReviewsPanel :provider-id="provider.id" type="sent" />
  189. </q-tab-panel>
  190. <q-tab-panel v-if="provider" name="received_reviews">
  191. <ProviderReviewsPanel :provider-id="provider.id" type="received" />
  192. </q-tab-panel>
  193. </q-tab-panels>
  194. </div>
  195. </q-card>
  196. </q-dialog>
  197. </template>
  198. <script setup>
  199. import { ref, useTemplateRef, onMounted, watch, computed } from "vue";
  200. import { useInputRules } from "src/composables/useInputRules";
  201. import { useDialogPluginComponent } from "quasar";
  202. import { useI18n } from "vue-i18n";
  203. import { createProvider, updateProvider } from "src/api/provider";
  204. import { useFormUpdateTracker } from "src/composables/useFormUpdateTracker";
  205. import { useSubmitHandler } from "src/composables/useSubmitHandler";
  206. import { dynamicCpfCnpjMask, validateCpfCnpj, calculateDailyPrices } from "src/helpers/utils";
  207. import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
  208. import UserSelect from "src/components/user/UserSelect.vue";
  209. import DefaultInputDatePicker from "src/components/defaults/DefaultInputDatePicker.vue";
  210. import DefaultCurrencyInput from "src/components/defaults/DefaultCurrencyInput.vue";
  211. import AddressesPanel from "src/pages/address/components/AddressesPanel.vue";
  212. import ProviderSpecialitiesPanel from "./ProviderSpecialitiesPanel.vue";
  213. import ProviderServicesTypesPanel from "./ProviderServicesTypesPanel.vue";
  214. import ProviderPaymentMethodsPanel from "./ProviderPaymentMethodsPanel.vue";
  215. import ProviderWorkingDaysPanel from "./ProviderWorkingDaysPanel.vue";
  216. import ProviderBlockedDaysPanel from "./ProviderBlockedDaysPanel.vue";
  217. import ProviderClientsBlocksPanel from "./ProviderClientsBlocksPanel.vue";
  218. import ProviderReviewsPanel from "./ProviderReviewsPanel.vue";
  219. defineEmits([
  220. ...useDialogPluginComponent.emits,
  221. ]);
  222. const { provider, title } = defineProps({
  223. provider: {
  224. type: Object,
  225. default: null,
  226. },
  227. title: {
  228. type: Function,
  229. default: () => useI18n().t("common.terms.title"),
  230. },
  231. });
  232. const { t } = useI18n();
  233. const { inputRules } = useInputRules();
  234. const approvalStatusOptions = computed(() => [
  235. { label: t("provider.approval_status.pending"), value: "pending" },
  236. { label: t("provider.approval_status.accepted"), value: "accepted" },
  237. { label: t("provider.approval_status.rejected"), value: "rejected" },
  238. ]);
  239. const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
  240. useDialogPluginComponent();
  241. const formRef = useTemplateRef("formRef");
  242. const tab = ref("data");
  243. const { form, getUpdatedFields, hasUpdatedFields } = useFormUpdateTracker({
  244. user_id: provider ? provider?.user_id : null,
  245. document: provider ? provider?.document : "",
  246. rg: provider ? provider?.rg : "",
  247. birth_date: provider ? provider?.birth_date : null,
  248. selfie_verified: provider? provider?.selfie_verified:false,
  249. document_verified: provider? provider?.document_verified:false,
  250. approval_status: provider ? provider?.approval_status : "pending",
  251. daily_price_8h: provider ? Number(provider?.daily_price_8h) : null,
  252. daily_price_6h: provider ? Number(provider?.daily_price_6h) : null,
  253. daily_price_4h: provider ? Number(provider?.daily_price_4h) : null,
  254. daily_price_2h: provider ? Number(provider?.daily_price_2h) : null,
  255. });
  256. const {
  257. loading,
  258. serverErrors,
  259. execute: submitForm,
  260. } = useSubmitHandler({
  261. onSuccess: () => onDialogOK(true),
  262. formRef: formRef,
  263. });
  264. const selectedUser = ref(null);
  265. const documentMask = computed(() => {
  266. return dynamicCpfCnpjMask(form.document);
  267. });
  268. const validateDocument = (val) => {
  269. if (!val) return true;
  270. return validateCpfCnpj(val) || t("validation.rules.cpf") + " / " + t("validation.rules.cnpj");
  271. };
  272. const onOKClick = async () => {
  273. if (provider) {
  274. await submitForm(() => updateProvider(getUpdatedFields.value, provider.id));
  275. } else {
  276. await submitForm(() => createProvider({ ...form }));
  277. }
  278. };
  279. watch(selectedUser, () => {
  280. form.user_id = selectedUser.value?.value;
  281. });
  282. watch(
  283. () => form.daily_price_8h,
  284. (newValue) => {
  285. const prices = calculateDailyPrices(newValue);
  286. form.daily_price_6h = prices.daily_price_6h;
  287. form.daily_price_4h = prices.daily_price_4h;
  288. form.daily_price_2h = prices.daily_price_2h;
  289. }
  290. );
  291. onMounted(async () => {
  292. if (provider) {
  293. selectedUser.value = {
  294. label: provider.user?.name || "",
  295. value: provider.user?.id,
  296. };
  297. }
  298. });
  299. </script>