You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

341 lines
12 KiB

2 years ago
  1. <template>
  2. <!-- eslint-disable vue/no-use-v-if-with-v-for,vue/no-confusing-v-for-v-if -->
  3. <v-card outlined class="rounded-xl px-3">
  4. <v-card-title> {{ $t("Locations") }}</v-card-title>
  5. <v-card-subtitle class="mt-0">
  6. <v-card outlined class="d-flex flex-row justify-space-between align-center px-3" style="border-radius: 12px"
  7. height="36" width="100%" :ripple="false" @click="dialog = true">
  8. <div style="color: #9c9c9c">{{ $t(searchBarTitle) }}</div>
  9. <v-img height="25" max-width="25" contain :src="require('~/assets/svg/search.svg')"></v-img>
  10. </v-card>
  11. </v-card-subtitle>
  12. <v-card-text class="ml-n4 mt-n3">
  13. <v-list>
  14. <v-list-group :value="!regionChecked.indexOf(region.id)" v-for="region in locations.slice(0, 8)"
  15. :key="region.id" no-action class="my-n3">
  16. <template v-slot:activator>
  17. <v-list-item-title>{{ region.region }}</v-list-item-title>
  18. </template>
  19. <template v-slot:prependIcon>
  20. <v-checkbox dense hide-details v-model="regionChecked" :value="region.id" @click.stop="
  21. () => {
  22. clickRegion(region.id);
  23. }
  24. "></v-checkbox>
  25. </template>
  26. <v-list>
  27. <v-list-group class="ml-5" :value="!countryChecked.indexOf(country.id)"
  28. v-for="country in region.countries" :key="country.id" no-action>
  29. <template v-slot:activator>
  30. <v-list-item-title>{{ country.country }}</v-list-item-title>
  31. </template>
  32. <template v-slot:prependIcon>
  33. <v-checkbox dense hide-details v-model="countryChecked" :value="country.id" @click.stop="
  34. () => {
  35. clickCountry(region.id, country.id);
  36. }
  37. "></v-checkbox>
  38. </template>
  39. <v-list-item v-for="(city, i) in country.cities" :key="i">
  40. <v-list-item-title class="ml-5">
  41. <v-checkbox dense hide-details v-model="cityChecked" :value="city.id" :label="city.city"
  42. @click.stop=""></v-checkbox>
  43. </v-list-item-title>
  44. </v-list-item>
  45. </v-list-group>
  46. </v-list>
  47. </v-list-group>
  48. </v-list>
  49. </v-card-text>
  50. <v-card-text>
  51. <v-btn outlined class="rounded-xl remove-upper tw-border-primary-2 tw-text-primary-1 mt-n10"
  52. style="padding: 10px auto" width="100%" @click="dialog = true">
  53. {{ $t("See more") }}
  54. </v-btn>
  55. </v-card-text>
  56. <v-dialog @click:outside="text = ''" v-model="dialog" width="644" height="618" class="rounded-xl">
  57. <v-card class="rounded-xl pa-4" width="100%" height="100%">
  58. <v-card-title>
  59. <v-row no-gutters class="d-flex justify-space-between">
  60. <div class="ml-n3">{{ $t("Select Location") }}</div>
  61. <v-img :src="require('~/assets/svg/X.svg')" max-width="24" max-height="24" contain @click="dialog = false">
  62. </v-img>
  63. </v-row>
  64. </v-card-title>
  65. <v-card-subtitle class="mt-5">
  66. <v-text-field outlined dense v-model="text" class="rounded-xl" :label="$t('Find Country/City ...')">
  67. <template v-slot:append>
  68. <v-img height="25" width="25" class="mt-n1" contain :src="require('~/assets/svg/search.svg')"></v-img>
  69. </template>
  70. </v-text-field>
  71. </v-card-subtitle>
  72. <v-card-text>
  73. <v-list>
  74. <v-list-group :value="
  75. !regionChecked.indexOf(region.id) ||
  76. (regionChild[i] > 0 &&
  77. regionChild[i] < locations[i].countries.length)
  78. " v-for="(region, i) in locations.slice(0, 8)" :key="region.id" no-action class="my-n3" v-if="
  79. regionChild[i] > 0 ||
  80. region.region.toLowerCase().includes(text.toLowerCase())
  81. ">
  82. <template v-slot:activator>
  83. <v-list-item-title>{{ region.region }}</v-list-item-title>
  84. </template>
  85. <template v-slot:prependIcon>
  86. <v-checkbox dense hide-details v-model="regionChecked" :value="region.id" @click.stop="
  87. () => {
  88. clickRegion(region.id);
  89. }
  90. "></v-checkbox>
  91. </template>
  92. <v-list>
  93. <v-list-group class="ml-5" :value="
  94. !countryChecked.indexOf(country.id) ||
  95. (countryChild[i][j] > 0 &&
  96. countryChild[i][j] <
  97. locations[i].countries[j].cities.length)
  98. " v-for="(country, j) in region.countries" :key="country.id" no-action v-if="
  99. countryChild[i][j] > 0 ||
  100. country.country.toLowerCase().includes(text.toLowerCase())
  101. ">
  102. <template v-slot:activator>
  103. <v-list-item-title>{{ country.country }}</v-list-item-title>
  104. </template>
  105. <template v-slot:prependIcon>
  106. <v-checkbox dense hide-details v-model="countryChecked" :value="country.id" @click.stop="
  107. () => {
  108. clickCountry(region.id, country.id);
  109. }
  110. "></v-checkbox>
  111. </template>
  112. <v-list-item v-for="city in country.cities" :key="city.id" v-if="
  113. city.city.toLowerCase().includes(text.toLowerCase()) ||
  114. text == ''
  115. ">
  116. <v-list-item-title class="ml-5">
  117. <v-checkbox dense hide-details v-model="cityChecked" :value="city.id" :label="city.city"
  118. @click.stop=""></v-checkbox>
  119. </v-list-item-title>
  120. </v-list-item>
  121. </v-list-group>
  122. </v-list>
  123. </v-list-group>
  124. </v-list>
  125. </v-card-text>
  126. </v-card>
  127. </v-dialog>
  128. </v-card>
  129. </template>
  130. <script>
  131. export default {
  132. props: ["locations", "searchBarTitle", "searchBarWidth"],
  133. data() {
  134. return {
  135. regionChecked: [],
  136. countryChecked: [],
  137. cityChecked: [],
  138. regionChild: [],
  139. countryChild: [],
  140. locationMapping: {},
  141. dialog: false,
  142. text: "",
  143. };
  144. },
  145. created() {
  146. this.countryChild = new Array(this.locations.length);
  147. for (let i = 0; i < this.locations.length; i++) {
  148. let regionId = this.locations[i].id;
  149. this.locationMapping[regionId] = {};
  150. this.countryChild[i] = [];
  151. this.regionChild[i] = this.locations[i].countries.length;
  152. for (let j = 0; j < this.locations[i].countries.length; j++) {
  153. let countryId = this.locations[i].countries[j].id;
  154. this.locationMapping[regionId][countryId] = [];
  155. if (this.locations[i].countries[j].cities != null) {
  156. this.countryChild[i][j] =
  157. this.locations[i].countries[j].cities.length;
  158. for (
  159. let k = 0;
  160. k < this.locations[i].countries[j].cities.length;
  161. k++
  162. ) {
  163. let cityId = this.locations[i].countries[j].cities[k].id;
  164. this.locationMapping[regionId][countryId].push(cityId);
  165. }
  166. }
  167. }
  168. }
  169. if (
  170. this.$route.query.region &&
  171. typeof this.$route.query.region == "object"
  172. ) {
  173. this.$route.query.region.map((c) => {
  174. this.regionChecked.push(parseInt(c));
  175. });
  176. } else if (
  177. this.$route.query.region &&
  178. typeof this.$route.query.region == "string"
  179. ) {
  180. this.$route.query.region.split(",").map((c) => {
  181. this.regionChecked.push(parseInt(c));
  182. });
  183. }
  184. if (
  185. this.$route.query.country &&
  186. typeof this.$route.query.country == "object"
  187. ) {
  188. this.$route.query.country.map((c) => {
  189. this.countryChecked.push(parseInt(c));
  190. });
  191. } else if (
  192. this.$route.query.country &&
  193. typeof this.$route.query.country == "string"
  194. ) {
  195. this.$route.query.country.split(",").map((c) => {
  196. this.countryChecked.push(parseInt(c));
  197. });
  198. }
  199. if (this.$route.query.city && typeof this.$route.query.city == "object") {
  200. this.$route.query.city.map((c) => {
  201. this.cityChecked.push(parseInt(c));
  202. });
  203. } else if (
  204. this.$route.query.city &&
  205. typeof this.$route.query.city == "string"
  206. ) {
  207. this.$route.query.city.split(",").map((c) => {
  208. this.cityChecked.push(parseInt(c));
  209. });
  210. }
  211. },
  212. watch: {
  213. regionChecked() {
  214. this.$emit("selectRegion", this.regionChecked);
  215. },
  216. countryChecked(to, from) {
  217. this.$emit("selectCountry", this.countryChecked);
  218. },
  219. cityChecked() {
  220. this.$emit("selectCity", this.cityChecked);
  221. },
  222. text() {
  223. // countryChild //
  224. let locationsLen = this.$props.locations.length;
  225. for (let i = 0; i < locationsLen; i++) {
  226. let countryLen = this.$props.locations[i].countries.length;
  227. for (let j = 0; j < countryLen; j++) {
  228. let cityNum = 0;
  229. let cityLen = this.$props.locations[i].countries[j].cities.length;
  230. for (let k = 0; k < cityLen; k++) {
  231. let cityString =
  232. this.$props.locations[i].countries[j].cities[k].city;
  233. if (cityString.toLowerCase().includes(this.text.toLowerCase()))
  234. cityNum++;
  235. }
  236. this.countryChild[i][j] = cityNum;
  237. }
  238. }
  239. // regionChild //
  240. locationsLen = this.$props.locations.length;
  241. for (let i = 0; i < locationsLen; i++) {
  242. let countryNum = 0;
  243. let countryLen = this.$props.locations[i].countries.length;
  244. for (let j = 0; j < countryLen; j++) {
  245. let countryString = this.$props.locations[i].countries[j].country;
  246. if (
  247. this.countryChild[i][j] > 0 ||
  248. countryString.toLowerCase().includes(this.text.toLowerCase())
  249. )
  250. countryNum++;
  251. }
  252. this.regionChild[i] = countryNum;
  253. }
  254. },
  255. },
  256. methods: {
  257. clickRegion(clickRegionId) {
  258. if (this.regionChecked.includes(clickRegionId)) {
  259. // add
  260. let countaryList = this.locationMapping[clickRegionId];
  261. for (const [country, cities] of Object.entries(countaryList)) {
  262. if (!this.countryChecked.includes(parseInt(country))) {
  263. this.countryChecked.push(parseInt(country));
  264. for (let i = 0; i < cities.length; i++) {
  265. let cityId = cities[i];
  266. if (!this.cityChecked.includes(cityId)) {
  267. this.cityChecked.push(cityId);
  268. }
  269. }
  270. }
  271. }
  272. } else {
  273. // delete
  274. let countryList = this.locationMapping[clickRegionId];
  275. for (const [country, cities] of Object.entries(countryList)) {
  276. let countryId = parseInt(country);
  277. let idxCountry = this.countryChecked.indexOf(countryId);
  278. if (idxCountry > -1) {
  279. this.countryChecked.splice(idxCountry, 1);
  280. for (let i = 0; i < cities.length; i++) {
  281. let cityId = cities[i];
  282. let idxCity = this.cityChecked.indexOf(cityId);
  283. if (idxCity > -1) {
  284. this.cityChecked.splice(idxCity, 1);
  285. }
  286. }
  287. }
  288. }
  289. }
  290. },
  291. clickCountry(regionid, clickCountryId) {
  292. if (this.countryChecked.includes(clickCountryId)) {
  293. // add
  294. let cityList = this.locationMapping[regionid][clickCountryId];
  295. for (let i = 0; i < cityList.length; i++) {
  296. let cityId = cityList[i];
  297. if (!this.cityChecked.includes(cityId)) this.cityChecked.push(cityId);
  298. }
  299. } else {
  300. // delete
  301. let cityList = this.locationMapping[regionid][clickCountaryId];
  302. for (let i = 0; i < cityList.length; i++) {
  303. let cityId = cityList[i];
  304. let idx = this.cityChecked.indexOf(cityId);
  305. if (idx > -1) this.cityChecked.splice(idx, 1);
  306. }
  307. }
  308. },
  309. },
  310. };
  311. </script>
  312. <style scoped lang="scss">
  313. :deep() {
  314. .v-text-field__details {
  315. display: none !important;
  316. }
  317. .v-input__append-inner {
  318. margin-top: 12px !important;
  319. }
  320. .v-input--selection-controls__input {
  321. i {
  322. color: #f5cda8 !important;
  323. }
  324. }
  325. .v-label {
  326. color: #232323 !important;
  327. margin-left: 20px;
  328. }
  329. }
  330. </style>