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.

532 lines
16 KiB

2 years ago
  1. <template>
  2. <div class="saveService xl:tw-max-w-[1246px] xl:tw-mx-auto">
  3. <div class="xl:tw-flex xl:tw-justify-between xl:tw-items-start">
  4. <userSidebar
  5. :userData="userData"
  6. :firstName="firstName"
  7. :lastName="lastName"
  8. class="tw-hidden xl:tw-block"
  9. >
  10. </userSidebar>
  11. <!-- <div class="xl:tw-hidden"></div> -->
  12. <div
  13. class="tw-bg-white xl:tw-p-[30px] xl:tw-rounded-[20px] xl:tw-min-w-[900px] xl:tw-max-w-[900px]"
  14. >
  15. <div
  16. class="tw-text-[20px] tw-font-bold tw-text-base-primary tw-mb-[20px] md:t24 md:tw-mb-[30px]"
  17. >
  18. <two-dots class="tw-mr-[30px]"></two-dots
  19. >{{ $t("userProfile.savedServices") }}
  20. </div>
  21. <section class="tw-mb-[80px] md:tw-mb-[30px] xl:tw-flex xl:tw-flex-row">
  22. <div class="tw-mb-[20px] md:tw-mb-[30px] xl:tw-mr-[55px]">
  23. <div
  24. class="tw-head-body tw-text-base-primary tw-mb-[10px] md:tw-text-[16px]"
  25. >
  26. Filter
  27. </div>
  28. <div class="md:tw-flex md:tw-flex-row">
  29. <div class="tw-mb-[20px] md:tw-mb-0">
  30. <select
  31. v-model="countrySelect"
  32. class="tw-w-[160px] tw-border tw-border-solid tw-border-neutrals-200 tw-rounded-[10px] tw-px-[15px] tw-py-[9px] tw-head-body tw-text-neutrals-500 tw-outline-none focus:tw-border-primary-1 md:tw-mr-[20px] md:tw-text-[16px]"
  33. >
  34. <option :value="0">All Countries</option>
  35. <option
  36. v-for="(item, index) in countryOptions"
  37. :key="index"
  38. :value="item.id"
  39. >
  40. {{ item.name }}
  41. </option>
  42. </select>
  43. <select
  44. v-model="citySelect"
  45. class="tw-w-[160px] tw-border tw-border-solid tw-border-neutrals-200 tw-rounded-[10px] tw-px-[15px] tw-py-[9px] tw-head-body tw-text-neutrals-500 tw-outline-none focus:tw-border-primary-1 md:tw-mr-[20px] md:tw-text-[16px]"
  46. >
  47. <option :value="0">All Cities</option>
  48. <option
  49. v-for="(item, index) in cityOptions"
  50. :key="index"
  51. :value="item.id"
  52. >
  53. {{ item.name }}
  54. </option>
  55. </select>
  56. </div>
  57. <select
  58. v-model="categorySelect"
  59. class="tw-w-[160px] tw-border tw-border-solid tw-border-neutrals-200 tw-rounded-[10px] tw-px-[15px] tw-py-[9px] tw-head-body tw-text-neutrals-500 tw-outline-none focus:tw-border-primary-1 md:tw-text-[16px]"
  60. >
  61. <option :value="0">All Categories</option>
  62. <option
  63. v-for="(item, index) in categoryOptions"
  64. :key="index"
  65. :value="item.id"
  66. >
  67. {{ item.name }}
  68. </option>
  69. </select>
  70. </div>
  71. </div>
  72. <div>
  73. <div
  74. class="tw-head-body tw-text-base-primary tw-mb-[10px] md:tw-text-[16px]"
  75. >
  76. Sort by
  77. </div>
  78. <select
  79. class="orangearrow tw-text-primary-1 tw-w-[260px] tw-border tw-border-solid tw-border-neutrals-200 tw-rounded-[10px] tw-px-[15px] tw-py-[9px] tw-head-body tw-outline-none focus:tw-border-primary-1 md:tw-text-[16px]"
  80. v-model="sortSelect"
  81. >
  82. <option
  83. v-for="(item, index) in sortBy"
  84. :key="index"
  85. :value="item.id"
  86. >
  87. {{ item.name }}
  88. </option>
  89. <!-- <option selected>Date : Newest to Oldest</option>
  90. <option>Date : Oldest to Newest</option> -->
  91. </select>
  92. </div>
  93. </section>
  94. <section
  95. class="tw-flex tw-flex-col tw-items-center tw-mb-[42px] md:tw-mb-[60px] xl:tw-mb-0"
  96. v-if="renderList.length === 0"
  97. >
  98. <img
  99. src="~/assets/svg/noServiceYet.svg"
  100. class="tw-max-w-[160px] md:tw-max-w-[210px] tw-mt-[60px]"
  101. alt=""
  102. />
  103. <div
  104. class="tw-text-[16px] tw-text-neutrals-800 tw-mb-[50px] md:tw-text-[18px] md:tw-mb-[60px]"
  105. >
  106. No Services yet ...
  107. </div>
  108. <button
  109. class="tw-text-[16px] tw-bg-primary-1 tw-text-white tw-px-[16px] tw-py-[10px] tw-rounded-[12px]"
  110. >
  111. Explore with ShowEasy
  112. </button>
  113. </section>
  114. <section v-else>
  115. <ServiceListCard
  116. class="tw-mb-[20px]"
  117. v-for="(item, index) in renderList"
  118. :key="index"
  119. :service="item"
  120. @remove-relation="updateServiceList()"
  121. >
  122. </ServiceListCard>
  123. </section>
  124. <section
  125. class="tw-flex tw-justify-end tw-py-2 tw-px-[10px] tw-mb-5 md:tw-mb-[30px]"
  126. >
  127. <pagination
  128. :pageLength="pageLength"
  129. @update="updateCurrentPage"
  130. ></pagination>
  131. </section>
  132. <div
  133. v-if="expiredList.length > 0"
  134. class="tw-border-[1px] tw-border-b-[0px] tw-border-solid tw-border-neutral-200 tw-mb-[30px] tw-hidden xl:tw-block"
  135. ></div>
  136. <section class="tw-pt-[30px]" v-if="expiredList.length > 0">
  137. <div
  138. class="tw-px-5 tw-py-[11px] tw-flex tw-justify-between tw-align-middle"
  139. >
  140. <div class="tw-body-2 tw-font-bold">
  141. {{ $t("Expired") }}
  142. </div>
  143. <button
  144. class="tw-text-[18px] tw-bg-white tw-text-secondary-default tw-w-fit"
  145. @click="deleteAllExpiredService"
  146. >
  147. {{ $t("Delete all") }}
  148. </button>
  149. </div>
  150. <ServiceListCard
  151. class="tw-mt-[20px] tw-opacity-70"
  152. v-for="(item, index) in expiredList"
  153. :key="index"
  154. :service="item"
  155. @remove-relation="updateServiceList()"
  156. >
  157. </ServiceListCard>
  158. </section>
  159. </div>
  160. </div>
  161. </div>
  162. </template>
  163. <script>
  164. import TwoDots from "@/components/TwoDots";
  165. import userSidebar from "@/components/user/userSidebar.vue";
  166. import ServiceListCard from "@/components/service/ServiceListCard";
  167. import pagination from "@/components/newComponent/pagination/pagination.vue";
  168. export default {
  169. name: "saveService",
  170. layout: "profile",
  171. components: {
  172. TwoDots,
  173. userSidebar,
  174. ServiceListCard,
  175. pagination,
  176. },
  177. data() {
  178. return {
  179. userData: {},
  180. countries: [],
  181. cities: [],
  182. categories: [],
  183. countryOptions: [],
  184. cityOptions: [],
  185. categoryOptions: [],
  186. serviceList: [],
  187. expiredList: [],
  188. categoryNameList: [],
  189. countryNameList: [],
  190. cityNameList: [],
  191. categorySelect: 0,
  192. countrySelect: 0,
  193. citySelect: 0,
  194. sortSelect: 0,
  195. firstName: "",
  196. lastName: "",
  197. sortBy: [
  198. {
  199. name: "Date : Newest to Oldest",
  200. id: 0,
  201. },
  202. {
  203. name: "Date : Oldest to Newest",
  204. id: 1,
  205. },
  206. ],
  207. currentPage: 1,
  208. perPageItems: 6,
  209. };
  210. },
  211. async created() {
  212. //this.$store.dispatch("updatePicture");
  213. if (process.browser) {
  214. window.addEventListener("resize", this.handleResize);
  215. }
  216. this.handleResize();
  217. // await this.fetchUserData();
  218. // await this.fetchSortCountry();
  219. // await this.getCategoryList();
  220. // await this.fetchSavedService();
  221. // await this.mapCountryOptions(this.serviceList, this.countries);
  222. // await this.mapCityOptions(this.serviceList, this.cities);
  223. // await this.mapCategoryOptions(this.serviceList, this.categories);
  224. },
  225. mounted() {
  226. this.$nextTick(() => {
  227. window.addEventListener("resize", this.onResize);
  228. });
  229. },
  230. destroyed() {
  231. if (process.browser) {
  232. window.removeEventListener("resize", this.handleResize);
  233. }
  234. },
  235. computed: {
  236. windowWidth() {
  237. if (process.client) {
  238. this.width = window.innerWidth;
  239. }
  240. return this.width;
  241. },
  242. serviceFilter() {
  243. const countryList = this.filterByCountry(
  244. this.serviceList,
  245. this.countrySelect
  246. );
  247. const cityList = this.filterByCity(countryList, this.citySelect);
  248. const categoryList = this.filterByCategory(cityList, this.categorySelect);
  249. const sortList = this.sortServiceList(categoryList, this.sortSelect);
  250. return sortList;
  251. },
  252. pageLength() {
  253. return Math.ceil(this.result / this.perPageItems);
  254. },
  255. result() {
  256. return this.serviceFilter.length;
  257. },
  258. renderList() {
  259. return this.sliceRenderList(this.serviceFilter);
  260. },
  261. },
  262. methods: {
  263. reloadPage() {
  264. this.tabs = "editPersonalInfo";
  265. },
  266. handleResize() {
  267. if (process.browser) {
  268. this.width = window.innerWidth;
  269. }
  270. },
  271. async fetchSortCountry() {
  272. await this.$axios
  273. .get(
  274. `t/exhibitions/locations?lang=${this.$i18n.localeProperties["langQuery"]}&sort=False`
  275. )
  276. .then((res) => {
  277. this.countries = res.data.country_ori;
  278. this.cities = res.data.city_ori;
  279. this.countryNameList = res.data.country_name_list;
  280. this.cityNameList = res.data.city_name_list;
  281. })
  282. .catch((err) => {
  283. console.log(err);
  284. });
  285. },
  286. async fetchUserData() {
  287. await this.$axios
  288. .get(
  289. `/member/users/${
  290. this.$auth.$storage.getUniversal("jwt").user_id
  291. }?jwt=${this.$auth.$storage.getUniversal("jwt").token}`
  292. )
  293. .then((res) => {
  294. this.userData = res.data;
  295. this.firstName = res.data.first_name;
  296. this.lastName = res.data.last_name;
  297. })
  298. .catch((err) => {
  299. console.log(err);
  300. });
  301. },
  302. async fetchSavedService() {
  303. await this.$axios
  304. .get(
  305. `/member/services?jwt=${
  306. this.$auth.$storage.getUniversal("jwt").token
  307. }&lang_code=${this.$i18n.localeProperties["langQuery"]}`
  308. )
  309. .then((result) => {
  310. this.serviceList = result.data.services;
  311. this.serviceList.forEach(function (item) {
  312. item.liked = true;
  313. item.isUserProfile = true;
  314. });
  315. this.serviceList = this.mapServiceLocationName(
  316. this.serviceList,
  317. this.countryNameList,
  318. this.cityNameList
  319. );
  320. this.serviceList = this.mapServiceCategoryName(
  321. this.serviceList,
  322. this.categoryNameList
  323. );
  324. this.expiredList = this.getExpiredService(this.serviceList);
  325. const expiredIds = this.expiredList.map((item) => item.id);
  326. this.serviceList = this.serviceList.filter(
  327. (item) => !expiredIds.includes(item.id)
  328. );
  329. })
  330. .catch((err) => {
  331. this.serviceList = [];
  332. console.log(err);
  333. });
  334. },
  335. async mapCountryOptions(services, countries) {
  336. const countryIds = services.map((item) => item.country);
  337. this.countryOptions = countries.filter((item) => {
  338. return countryIds.includes(item.id);
  339. });
  340. },
  341. async mapCityOptions(services, cities) {
  342. const cityIds = services.map((item) => item.city);
  343. this.cityOptions = cities.filter((item) => {
  344. return cityIds.includes(item.id);
  345. });
  346. },
  347. async mapCategoryOptions(services, categories) {
  348. const categoryIds = services.map((item) => item.category);
  349. this.categoryOptions = categories.filter((item) => {
  350. return categoryIds.includes(item.id);
  351. });
  352. },
  353. async getCategoryList() {
  354. await this.$axios
  355. .get(
  356. `/service/category?lang_code=${this.$i18n.localeProperties["langQuery"]}`
  357. )
  358. .then((result) => {
  359. this.categories = result.data.map((item) => {
  360. return {
  361. id: item.id,
  362. name: item.language_text[0].text,
  363. };
  364. });
  365. result.data.forEach((item) => {
  366. this.categoryNameList[item.id] = item.language_text[0].text;
  367. });
  368. return result.data;
  369. })
  370. .catch((err) => {
  371. console.log(err);
  372. });
  373. },
  374. mapServiceCategoryName(data, categoryList) {
  375. data = data.map((item) => {
  376. Number(item.category) > 0
  377. ? (item.categoryName = categoryList[item.category])
  378. : (item.categoryName = "");
  379. return item;
  380. });
  381. return data;
  382. },
  383. mapServiceLocationName(data, countryList, cityList) {
  384. data = data.map((item) => {
  385. Number(item.country) > 0
  386. ? (item.countryName = countryList[item.country])
  387. : (item.countryName = "");
  388. return item;
  389. });
  390. data = data.map((item) => {
  391. Number(item.city) > 0
  392. ? (item.cityName = cityList[item.city])
  393. : (item.cityName = "");
  394. return item;
  395. });
  396. return data;
  397. },
  398. sortServiceList(data, sort) {
  399. switch (sort) {
  400. case 0:
  401. function NewToOld(a, b) {
  402. if (
  403. a.launch_date.replace(/-/g, "") < b.launch_date.replace(/-/g, "")
  404. )
  405. return 1;
  406. if (
  407. a.launch_date.replace(/-/g, "") > b.launch_date.replace(/-/g, "")
  408. )
  409. return -1;
  410. return 0;
  411. }
  412. return data.sort(NewToOld);
  413. case 1:
  414. function OldToNew(a, b) {
  415. if (
  416. a.launch_date.replace(/-/g, "") > b.launch_date.replace(/-/g, "")
  417. )
  418. return 1;
  419. if (
  420. a.launch_date.replace(/-/g, "") < b.launch_date.replace(/-/g, "")
  421. )
  422. return -1;
  423. return 0;
  424. }
  425. return data.sort(OldToNew);
  426. default:
  427. return data;
  428. }
  429. },
  430. filterByCategory(data, category) {
  431. if (Number(category) < 1) {
  432. return data;
  433. } else {
  434. return data.filter(
  435. (item) => Number(item.category) === Number(category)
  436. );
  437. }
  438. },
  439. filterByCity(data, city) {
  440. if (Number(city) < 1) {
  441. return data;
  442. } else {
  443. return data.filter((item) => Number(item.city) === Number(city));
  444. }
  445. },
  446. filterByCountry(data, country) {
  447. if (Number(country) < 1) {
  448. return data;
  449. } else {
  450. return data.filter((item) => Number(item.country) === Number(country));
  451. }
  452. },
  453. updateCurrentPage(value) {
  454. this.currentPage = value;
  455. },
  456. sliceRenderList(data) {
  457. return data.slice(
  458. (this.currentPage - 1) * this.perPageItems,
  459. this.currentPage * this.perPageItems
  460. );
  461. },
  462. getExpiredService(data) {
  463. const result = data.filter((item) => {
  464. const isItemExpired = this.calculateLaunchDays(
  465. item.launch_date,
  466. item.launch_days
  467. );
  468. return isItemExpired;
  469. });
  470. return result;
  471. },
  472. calculateLaunchDays(launchDate, launchDays) {
  473. const dateObj = new Date();
  474. const year = dateObj.getFullYear();
  475. const month = dateObj.getMonth() + 1;
  476. const date = dateObj.getDate();
  477. const todayStr = `${year}-${month}-${date}`;
  478. const daySeconds = 1000 * 60 * 60 * 24;
  479. const today = new Date(todayStr);
  480. const launch = new Date(launchDate);
  481. const result = parseInt(Math.abs(today - launch) / daySeconds);
  482. if (launchDate.replace(/-/g, "") > todayStr.replace(/-/g, ""))
  483. return true;
  484. if (result > launchDays) {
  485. return true;
  486. } else {
  487. return false;
  488. }
  489. },
  490. updateServiceList() {
  491. this.$nextTick(() => {
  492. this.fetchSavedService();
  493. });
  494. },
  495. async deleteAllExpiredService() {
  496. const requests = [];
  497. this.expiredList.forEach((item) => {
  498. const axiosObj = this.$axios({
  499. url: `${process.env.BASE_URL}member/services/${item.id}?jwt=${
  500. this.$auth.$storage.getUniversal("jwt").token
  501. }`,
  502. method: "delete",
  503. });
  504. requests.push(axiosObj);
  505. });
  506. Promise.all(requests)
  507. .then((res) => {
  508. console.log(res);
  509. this.expiredList = [];
  510. })
  511. .catch((err) => {
  512. console.log(err);
  513. });
  514. },
  515. },
  516. };
  517. </script>
  518. <style scoped lang="scss">
  519. select {
  520. background-image: url("~/assets/svg/dropdownarrow.svg");
  521. width: auto;
  522. height: auto;
  523. background-position: right 12px center;
  524. background-repeat: no-repeat;
  525. }
  526. .orangearrow {
  527. background-image: url("~/assets/svg/orangeArrow.svg");
  528. }
  529. </style>