AddEditProviderDialog.vue 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <template>
  2. <q-dialog ref="dialogRef" @hide="onDialogHide">
  3. <q-card class="q-dialog-plugin overflow-hidden" style="width: 1000px; max-width: 90vw">
  4. <DefaultDialogHeader :title="title" @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-tabs>
  9. <q-separator v-if="provider" />
  10. <q-tab-panels v-model="tab" animated>
  11. <q-tab-panel name="data">
  12. <q-form ref="formRef" @submit="onOKClick">
  13. <q-card-section class="row q-col-gutter-sm">
  14. <UserSelect
  15. v-model="selectedUser"
  16. :label="$t('common.terms.user')"
  17. :rules="[inputRules.required]"
  18. :error="!!serverErrors?.user_id"
  19. :error-message="serverErrors?.user_id"
  20. :initial-id="provider ? provider.user_id : null"
  21. class="col-md-6 col-12"
  22. />
  23. <q-input
  24. v-model="form.document"
  25. :mask="documentMask"
  26. fill-mask
  27. unmasked-value
  28. :label="$t('provider.fields.document')"
  29. :rules="[inputRules.required, validateDocument]"
  30. :error="!!serverErrors?.document"
  31. :error-message="serverErrors?.document"
  32. class="col-md-6 col-12"
  33. />
  34. <q-input
  35. v-model="form.rg"
  36. mask="##.###.###-#"
  37. fill-mask
  38. :label="$t('provider.fields.rg')"
  39. :error="!!serverErrors?.rg"
  40. :error-message="serverErrors?.rg"
  41. class="col-md-6 col-12"
  42. />
  43. <DefaultInputDatePicker
  44. v-model:untreated-date="form.birth_date"
  45. :label="$t('provider.fields.birth_date')"
  46. :error="serverErrors?.birth_date"
  47. :error-message="serverErrors?.birth_date"
  48. class="col-md-6 col-12"
  49. />
  50. <DefaultCurrencyInput
  51. v-model="form.daily_price_8h"
  52. :label="$t('provider.fields.daily_price_8h')"
  53. :error="!!serverErrors?.daily_price_8h"
  54. :error-message="serverErrors?.daily_price_8h"
  55. :hint="$t('provider.hints.daily_price')"
  56. lazy-rules
  57. class="col-md-3 col-6"
  58. />
  59. <DefaultCurrencyInput
  60. v-model="form.daily_price_6h"
  61. :label="$t('provider.fields.daily_price_6h')"
  62. :error="!!serverErrors?.daily_price_6h"
  63. :error-message="serverErrors?.daily_price_6h"
  64. disable
  65. class="col-md-3 col-6"
  66. />
  67. <DefaultCurrencyInput
  68. v-model="form.daily_price_4h"
  69. :label="$t('provider.fields.daily_price_4h')"
  70. :error="!!serverErrors?.daily_price_4h"
  71. :error-message="serverErrors?.daily_price_4h"
  72. disable
  73. class="col-md-3 col-6"
  74. />
  75. <DefaultCurrencyInput
  76. v-model="form.daily_price_2h"
  77. :label="$t('provider.fields.daily_price_2h')"
  78. :error="!!serverErrors?.daily_price_2h"
  79. :error-message="serverErrors?.daily_price_2h"
  80. disable
  81. class="col-md-3 col-6"
  82. />
  83. <div class="col-12">
  84. <q-checkbox
  85. v-model="form.is_approved"
  86. :label="$t('provider.fields.is_approved')"
  87. />
  88. </div>
  89. <div class="col-12 q-mt-md">
  90. <div class="row q-col-gutter-md">
  91. <div class="col-auto flex items-center">
  92. <q-avatar size="80px" color="grey-3">
  93. <q-icon name="mdi-account" size="50px" color="grey-6" />
  94. </q-avatar>
  95. </div>
  96. <div class="col row q-col-gutter-sm">
  97. <div class="col-md-6 col-12">
  98. <div class="text-subtitle2 text-grey-7">
  99. {{ $t('provider.fields.average_rating') }}
  100. </div>
  101. <div class="text-body1 text-weight-medium">
  102. {{ provider?.average_rating || '-' }}
  103. </div>
  104. </div>
  105. <div class="col-md-6 col-12">
  106. <div class="text-subtitle2 text-grey-7">
  107. {{ $t('provider.fields.total_services') }}
  108. </div>
  109. <div class="text-body1 text-weight-medium">
  110. {{ provider?.total_services || '0' }}
  111. </div>
  112. </div>
  113. <div class="col-md-6 col-12">
  114. <div class="text-subtitle2 text-grey-7">
  115. {{ $t('provider.fields.selfie_verified') }}
  116. </div>
  117. <div class="text-body1 text-weight-medium">
  118. {{ provider?.selfie_verified ? $t('common.status.yes') : $t('common.status.no') }}
  119. </div>
  120. </div>
  121. <div class="col-md-6 col-12">
  122. <div class="text-subtitle2 text-grey-7">
  123. {{ $t('provider.fields.document_verified') }}
  124. </div>
  125. <div class="text-body1 text-weight-medium">
  126. {{ provider?.document_verified ? $t('common.status.yes') : $t('common.status.no') }}
  127. </div>
  128. </div>
  129. </div>
  130. </div>
  131. </div>
  132. </q-card-section>
  133. <q-card-actions align="center">
  134. <q-btn color="primary" label="Cancel" @click="onDialogCancel" />
  135. <q-space />
  136. <q-btn color="primary" label="OK" :type="'submit'" :loading="loading" :disable="!hasUpdatedFields" />
  137. </q-card-actions>
  138. </q-form>
  139. </q-tab-panel>
  140. <q-tab-panel v-if="provider" name="addresses">
  141. <AddressesPanel :source="'provider'" :source-id="provider.id" />
  142. </q-tab-panel>
  143. </q-tab-panels>
  144. </q-card>
  145. </q-dialog>
  146. </template>
  147. <script setup>
  148. import { ref, useTemplateRef, onMounted, watch, computed } from "vue";
  149. import { useInputRules } from "src/composables/useInputRules";
  150. import { useDialogPluginComponent } from "quasar";
  151. import { useI18n } from "vue-i18n";
  152. import { createProvider, updateProvider } from "src/api/provider";
  153. import { useFormUpdateTracker } from "src/composables/useFormUpdateTracker";
  154. import { useSubmitHandler } from "src/composables/useSubmitHandler";
  155. import { dynamicCpfCnpjMask, validateCpfCnpj, calculateDailyPrices } from "src/helpers/utils";
  156. import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
  157. import UserSelect from "src/components/user/UserSelect.vue";
  158. import DefaultInputDatePicker from "src/components/defaults/DefaultInputDatePicker.vue";
  159. import DefaultCurrencyInput from "src/components/defaults/DefaultCurrencyInput.vue";
  160. import AddressesPanel from "src/pages/address/components/AddressesPanel.vue";
  161. defineEmits([
  162. ...useDialogPluginComponent.emits,
  163. ]);
  164. const { provider, title } = defineProps({
  165. provider: {
  166. type: Object,
  167. default: null,
  168. },
  169. title: {
  170. type: Function,
  171. default: () => useI18n().t("common.terms.title"),
  172. },
  173. });
  174. const { t } = useI18n();
  175. const { inputRules } = useInputRules();
  176. const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
  177. useDialogPluginComponent();
  178. const formRef = useTemplateRef("formRef");
  179. const tab = ref("data");
  180. const { form, getUpdatedFields, hasUpdatedFields } = useFormUpdateTracker({
  181. user_id: provider ? provider?.user_id : null,
  182. document: provider ? provider?.document : "",
  183. rg: provider ? provider?.rg : "",
  184. birth_date: provider ? provider?.birth_date : null,
  185. is_approved: provider ? provider?.is_approved : false,
  186. daily_price_8h: provider ? Number(provider?.daily_price_8h) : null,
  187. daily_price_6h: provider ? Number(provider?.daily_price_6h) : null,
  188. daily_price_4h: provider ? Number(provider?.daily_price_4h) : null,
  189. daily_price_2h: provider ? Number(provider?.daily_price_2h) : null,
  190. });
  191. // const birthDate = ref(null);
  192. const {
  193. loading,
  194. serverErrors,
  195. execute: submitForm,
  196. } = useSubmitHandler({
  197. onSuccess: () => onDialogOK(true),
  198. formRef: formRef,
  199. });
  200. const selectedUser = ref(null);
  201. const documentMask = computed(() => {
  202. return dynamicCpfCnpjMask(form.document);
  203. });
  204. const validateDocument = (val) => {
  205. if (!val) return true;
  206. return validateCpfCnpj(val) || t("validation.rules.cpf") + " / " + t("validation.rules.cnpj");
  207. };
  208. const onOKClick = async () => {
  209. if (provider) {
  210. await submitForm(() => updateProvider(getUpdatedFields.value, provider.id));
  211. } else {
  212. await submitForm(() => createProvider({ ...form }));
  213. }
  214. };
  215. watch(selectedUser, () => {
  216. form.user_id = selectedUser.value?.value;
  217. });
  218. watch(
  219. () => form.daily_price_8h,
  220. (newValue) => {
  221. const prices = calculateDailyPrices(newValue);
  222. form.daily_price_6h = prices.daily_price_6h;
  223. form.daily_price_4h = prices.daily_price_4h;
  224. form.daily_price_2h = prices.daily_price_2h;
  225. }
  226. );
  227. onMounted(async () => {
  228. if (provider) {
  229. selectedUser.value = {
  230. label: provider.user?.name || "",
  231. value: provider.user?.id,
  232. };
  233. }
  234. });
  235. </script>