StateSelect.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. <template>
  2. <DefaultSelect
  3. v-model="selectedState"
  4. v-bind="$attrs"
  5. use-input
  6. hide-selected
  7. fill-input
  8. clearable
  9. :options="stateOptions"
  10. :label
  11. :loading
  12. :placeholder
  13. @filter="filterFn"
  14. >
  15. <template #no-option>
  16. <q-item>
  17. <q-item-section class="text-grey">
  18. {{ $t("http.errors.no_records_found") }}
  19. </q-item-section>
  20. </q-item>
  21. </template>
  22. </DefaultSelect>
  23. </template>
  24. <script setup>
  25. import { getStates } from "src/api/state";
  26. import { ref, watch } from "vue";
  27. import { normalizeString } from "src/helpers/utils";
  28. import { useI18n } from "vue-i18n";
  29. import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
  30. const emit = defineEmits(["selectedCountryId"]);
  31. const { country, placeholder } = defineProps({
  32. country: {
  33. type: Object,
  34. required: false,
  35. default: () => ({
  36. label: "Brasil",
  37. value: 1,
  38. }),
  39. },
  40. placeholder: {
  41. type: String,
  42. default: () =>
  43. useI18n().t("common.actions.search") +
  44. " " +
  45. useI18n().t("ui.navigation.state"),
  46. },
  47. label: {
  48. type: String,
  49. default: () => useI18n().t("ui.navigation.state"),
  50. },
  51. });
  52. const selectedState = defineModel({ type: Object });
  53. const loading = ref(false);
  54. const baseOptions = ref([]);
  55. const stateOptions = ref([]);
  56. const ensureOnlyPossibleOptions = (country_id) => {
  57. stateOptions.value = country_id
  58. ? baseOptions.value.filter((s) => s.country_id === country_id)
  59. : baseOptions.value;
  60. };
  61. const filterFn = async (val, update) => {
  62. if (baseOptions.value.length === 0) {
  63. loading.value = true;
  64. try {
  65. const data = await getStates();
  66. baseOptions.value = data.map((s) => ({
  67. label: s.name,
  68. value: s.id,
  69. code: s.code,
  70. country_id: s.country_id,
  71. }));
  72. } catch (e) {
  73. console.error(e);
  74. } finally {
  75. loading.value = false;
  76. }
  77. }
  78. ensureOnlyPossibleOptions(country?.value);
  79. const needle = normalizeString(val);
  80. if (needle) {
  81. stateOptions.value = stateOptions.value.filter(
  82. (v) =>
  83. normalizeString(v.label).includes(needle) ||
  84. normalizeString(v.code).includes(needle),
  85. );
  86. }
  87. update();
  88. };
  89. const selectStateById = (id) => {
  90. if (selectedState.value?.value === id) return;
  91. selectedState.value = baseOptions.value.find((s) => s.value === id);
  92. };
  93. const selectStateByName = (name) => {
  94. if (selectedState.value?.label === name) return;
  95. selectedState.value = baseOptions.value.find((s) => s.label === name);
  96. };
  97. const selectStateByCode = (code) => {
  98. if (selectedState.value?.code === code) return;
  99. selectedState.value = baseOptions.value.find((s) => s.code === code);
  100. };
  101. watch(
  102. () => country,
  103. (value, oldValue) => {
  104. if (!oldValue) return;
  105. if (value?.value != oldValue?.value && value?.value != selectedState.value?.country_id) {
  106. selectedState.value = null;
  107. }
  108. if (value && baseOptions.value.length > 0) {
  109. ensureOnlyPossibleOptions(value.value);
  110. }
  111. },
  112. );
  113. watch(selectedState, () => {
  114. if (selectedState.value?.country_id) {
  115. emit("selectedCountryId", selectedState.value.country_id);
  116. }
  117. });
  118. defineExpose({
  119. selectStateById,
  120. selectStateByName,
  121. selectStateByCode,
  122. });
  123. </script>