@wikicasa-dev/utilities 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +32 -2
  2. package/dist/index.d.ts +3 -3
  3. package/dist/main.d.ts +0 -0
  4. package/dist/utilities.cjs +4 -4
  5. package/dist/utilities.iife.js +4 -4
  6. package/dist/utilities.mjs +892 -1181
  7. package/dist/utils/DateUtils.d.ts +1 -0
  8. package/dist/utils/FunctionUtils.d.ts +2 -2
  9. package/dist/utils/StringUtils.d.ts +1 -0
  10. package/index.html +13 -0
  11. package/package.json +4 -6
  12. package/src/custom/constants.ts +3 -0
  13. package/src/custom/icons.ts +63 -0
  14. package/src/custom/leaflet_map.ts +946 -0
  15. package/src/index.ts +171 -0
  16. package/src/main.ts +1 -0
  17. package/src/services/agencyAPI.ts +105 -0
  18. package/src/services/geographyAPI.ts +129 -0
  19. package/src/services/insightsAPI.ts +20 -0
  20. package/src/services/mailAPI.ts +89 -0
  21. package/src/services/placesAPI.ts +72 -0
  22. package/src/services/portfolioCustomerAPI.ts +16 -0
  23. package/src/services/publicUserAPI.ts +216 -0
  24. package/src/services/realEstateAPI.ts +133 -0
  25. package/src/services/requestAPI.ts +40 -0
  26. package/src/services/servicesUtils.ts +27 -0
  27. package/src/services/statisticsAPI.ts +84 -0
  28. package/src/services/valuationAPI.ts +45 -0
  29. package/src/services/wikicasaPro.ts +25 -0
  30. package/src/utils/ArrayUtils.ts +2 -0
  31. package/src/utils/ColorUtils.ts +11 -0
  32. package/src/utils/CookieUtils.ts +43 -0
  33. package/src/utils/CurrencyUtils.ts +18 -0
  34. package/src/utils/DOMUtils.ts +28 -0
  35. package/src/utils/DateUtils.ts +9 -0
  36. package/src/utils/DeviceDetectionUtils.ts +17 -0
  37. package/src/utils/EmailUtils.ts +45 -0
  38. package/src/utils/FavoriteUtils.ts +19 -0
  39. package/src/utils/FunctionUtils.ts +29 -0
  40. package/src/utils/GAutocompleteUtils.ts +70 -0
  41. package/src/utils/GenericUtils.ts +37 -0
  42. package/src/utils/LazyLoadingBg.ts +18 -0
  43. package/src/utils/MapUtils.ts +118 -0
  44. package/src/utils/NumberUtils.ts +90 -0
  45. package/src/utils/ObjectUtils.ts +34 -0
  46. package/src/utils/ObserverUtils.ts +32 -0
  47. package/src/utils/PermissionUtils.ts +41 -0
  48. package/src/utils/RESB_UrlBuilder.ts +99 -0
  49. package/src/utils/RequestUtils.ts +20 -0
  50. package/src/utils/StringUtils.ts +75 -0
  51. package/src/utils/URLBuilderUtils.ts +21 -0
  52. package/src/utils/URLPagesFactory.ts +20 -0
  53. package/src/vite-env.d.ts +1 -0
  54. package/tsconfig.json +38 -0
  55. package/vite.config.ts +42 -0
  56. package/dist/utils/AppRedirectUtils.d.ts +0 -1
  57. package/dist/utils/GAEvents.d.ts +0 -2
@@ -0,0 +1,17 @@
1
+ declare global {
2
+ interface Window {
3
+ MSStream: any;
4
+ }
5
+ }
6
+
7
+ export const isiOSDevice = (): boolean =>
8
+ /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
9
+
10
+ export const isMobile = (): boolean =>
11
+ /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
12
+ navigator.userAgent
13
+ );
14
+
15
+ export const isSafari = (): boolean => {
16
+ return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
17
+ };
@@ -0,0 +1,45 @@
1
+ import type { Nullable } from "@wikicasa-dev/types";
2
+
3
+ const isGmailAddress = (email: string): boolean => email.includes("@gmail");
4
+
5
+ async function hash256(string: string): Promise<string> {
6
+ const utf8 = new TextEncoder().encode(string);
7
+ const hashBuffer = await crypto.subtle.digest("SHA-256", utf8);
8
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
9
+ const hashHex = hashArray
10
+ .map((bytes) => bytes.toString(16).padStart(2, "0"))
11
+ .join("");
12
+ return hashHex;
13
+ }
14
+
15
+ const normalizeGmail = (email: string): string => {
16
+ const emailTokens = email.split("@");
17
+ if (emailTokens.length < 2)
18
+ throw new Error("The email has nothing before the '@' symbol");
19
+
20
+ const usernameAddress = emailTokens[0];
21
+ let normalizeUsernameAddress = "";
22
+
23
+ for (const char of usernameAddress) {
24
+ //Removing the dot symbol
25
+ if (char === ".") continue;
26
+ //If we come across into a sum symbol, we will break the valuation
27
+ if (char === "+") break;
28
+ normalizeUsernameAddress += char;
29
+ }
30
+ return `${normalizeUsernameAddress}@${emailTokens[1]}`;
31
+ };
32
+
33
+ export const hashEmail = (
34
+ emailToNormalize: Nullable<string>
35
+ ): Promise<string> => {
36
+ if (!emailToNormalize || !emailToNormalize.trim())
37
+ throw new Error("The email in null or empty");
38
+
39
+ let _emailToNormalize = emailToNormalize;
40
+
41
+ if (isGmailAddress(_emailToNormalize))
42
+ _emailToNormalize = normalizeGmail(emailToNormalize);
43
+
44
+ return hash256(_emailToNormalize);
45
+ };
@@ -0,0 +1,19 @@
1
+ export const showRemoveFavoritesIcons = (id: number): void => {
2
+ const elems = document.querySelectorAll(`a[class^=fav][data-id='${id}']`);
3
+ elems.forEach((e) => {
4
+ if (e.classList.contains("fav-save"))
5
+ (e as HTMLAnchorElement).style.display = "none";
6
+ else if (e.classList.contains("fav-remove"))
7
+ (e as HTMLAnchorElement).style.display = "block";
8
+ });
9
+ };
10
+
11
+ export const showAddFavoritesIcon = (id: number): void => {
12
+ const elems = document.querySelectorAll(`a[class^=fav][data-id='${id}']`);
13
+ elems.forEach((e) => {
14
+ if (e.classList.contains("fav-save"))
15
+ (e as HTMLAnchorElement).style.display = "block";
16
+ else if (e.classList.contains("fav-remove"))
17
+ (e as HTMLAnchorElement).style.display = "none";
18
+ });
19
+ };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Determine whether the given `functionToCheck` is a Promise.
3
+ * @param {*} functionToCheck
4
+ * @returns a function correctly typed as Promise
5
+ */
6
+ export function isPromise<T>(functionToCheck: any): Promise<T> {
7
+ if (!functionToCheck || !(typeof functionToCheck.then === "function"))
8
+ throw new Error("The provide function is not a promise");
9
+
10
+ return functionToCheck as Promise<T>;
11
+ }
12
+
13
+
14
+ export function debounce<T extends (...args: any[]) => any, TReturn>(timeout: {
15
+ id?: ReturnType<typeof setTimeout>,
16
+ delay: number
17
+ }, func: T): (...args: any[]) => Promise<TReturn> {
18
+ return (...args: any[]): Promise<TReturn> => new Promise((resolve, reject) => {
19
+ timeout.id && clearTimeout(timeout.id);
20
+ timeout.id = setTimeout(() => {
21
+ try {
22
+ const res = func(...args) as TReturn;
23
+ resolve(res);
24
+ } catch (err) {
25
+ reject(err)
26
+ }
27
+ }, timeout.delay);
28
+ })
29
+ }
@@ -0,0 +1,70 @@
1
+ import type { Place, GPlaceDetails } from "@wikicasa-dev/types";
2
+ import { cleanASCII, formatAddress } from "@utils/StringUtils";
3
+ import { getPlacesDetails, guessPlace } from "@services/geographyAPI";
4
+
5
+ export const googlePlaceConverter = async (
6
+ gPlace: GPlaceDetails,
7
+ address: string
8
+ ): Promise<Place> => {
9
+ const place = {} as Place;
10
+
11
+ for (let i = 0; i < gPlace["address_components"].length; i++) {
12
+ if (
13
+ gPlace["address_components"][i].types.indexOf(
14
+ "administrative_area_level_3"
15
+ ) !== -1
16
+ ) {
17
+ place.city = gPlace["address_components"][i].long_name;
18
+ } else if (
19
+ gPlace["address_components"][i].types.indexOf("locality") !== -1
20
+ ) {
21
+ place.locality = gPlace["address_components"][i].long_name;
22
+ } else if (gPlace["address_components"][i].types.indexOf("route") !== -1) {
23
+ place.streetName = gPlace["address_components"][i].long_name;
24
+ } else if (
25
+ gPlace["address_components"][i].types.indexOf("street_number") !== -1
26
+ ) {
27
+ place.streetNumber = gPlace["address_components"][i].long_name;
28
+ } else if (
29
+ gPlace["address_components"][i].types.indexOf("postal_code") !== -1
30
+ ) {
31
+ place.zip = gPlace["address_components"][i].long_name;
32
+ }
33
+ }
34
+
35
+ place.latitude = gPlace["geometry"].location.lat;
36
+ place.longitude = gPlace["geometry"].location.lng;
37
+
38
+ place.address = cleanASCII(address);
39
+
40
+ if (typeof place.streetNumber === "undefined") place.streetNumber = null;
41
+
42
+ let res = await guessPlace(place.latitude, place.longitude);
43
+
44
+ delete res.city;
45
+ delete res.locality;
46
+
47
+ res = { ...res, ...place };
48
+
49
+ /* FIX FOR GOOGLE AUTOCOMPLETE MISSING STREET NUMBER */
50
+ if (!res.streetNumber) {
51
+ const term = parseInt(res.address.split(",")[1]);
52
+ const zip = parseInt(res.zip);
53
+
54
+ if (term && term !== zip) res.streetNumber = term.toString();
55
+ }
56
+
57
+ return res;
58
+ };
59
+
60
+ export const getPlaceFromGAutocomplete = async (
61
+ placeId: string,
62
+ label: string
63
+ ): Promise<{ place: Place; address: string }> => {
64
+ const gPlaceDetails = await getPlacesDetails(placeId);
65
+ const place = await googlePlaceConverter(gPlaceDetails, label);
66
+ const address = place.streetName
67
+ ? formatAddress(place.streetName, place.streetNumber || "", place.cityName)
68
+ : place.address;
69
+ return { place, address };
70
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @param fn - pass null to set a generic await
3
+ * @param timeoutMs time to wait before firing the callback function
4
+ **/
5
+ export const awaitableSetTimeout = (
6
+ fn: (() => void) | null,
7
+ timeoutMs: number
8
+ ): Promise<void> =>
9
+ new Promise((resolve, reject) => {
10
+ setTimeout(() => {
11
+ try {
12
+ fn && fn(); //calling the callback function
13
+ resolve();
14
+ } catch (error) {
15
+ reject();
16
+ }
17
+ }, timeoutMs);
18
+ });
19
+
20
+ export function createCustomEvent(
21
+ event: string,
22
+ params?: CustomEventInit
23
+ ): Event {
24
+ if (typeof window.CustomEvent === "function") {
25
+ return new CustomEvent(event, params);
26
+ }
27
+
28
+ params = params || { bubbles: false, cancelable: false, detail: undefined };
29
+ const evt = document.createEvent("CustomEvent");
30
+ evt.initCustomEvent(
31
+ event,
32
+ !!params.bubbles,
33
+ !!params.cancelable,
34
+ params.detail
35
+ );
36
+ return evt;
37
+ }
@@ -0,0 +1,18 @@
1
+ document.addEventListener("DOMContentLoaded", () => {
2
+ const lazyImages = document.getElementsByClassName("lazy");
3
+ if (lazyImages.length === 0)
4
+ return;
5
+
6
+ for (const img of lazyImages) {
7
+ const lazyImage = (img as HTMLImageElement);
8
+ /* The lazy loading is given by the attribute loading="lazy" of images! */
9
+ lazyImage.onload = (): void => {
10
+ const {currentSrc} = lazyImage;
11
+ lazyImage.style.cssText = "display:none";
12
+ /* Retrieving the parent */
13
+ const parent = lazyImage.parentNode as HTMLElement;
14
+ parent.style.backgroundImage = "url(\"" + currentSrc + "\")";
15
+ }
16
+ }
17
+
18
+ });
@@ -0,0 +1,118 @@
1
+ import type { LatLng } from "leaflet";
2
+ import { encode } from "google-polyline";
3
+
4
+ import Leaflet_map from "../custom/leaflet_map";
5
+
6
+ declare global {
7
+ interface Window {
8
+ _mapRange?: number;
9
+ }
10
+ }
11
+
12
+ export function parsePoints(polygonFromMap: string): Array<LatLng> | undefined {
13
+ if (!polygonFromMap) return;
14
+
15
+ const numbers: RegExpMatchArray | null =
16
+ polygonFromMap.match(/[-]?[\d]*[.]?[\d]+/g);
17
+
18
+ if (!numbers) return;
19
+
20
+ const latLngs: Array<LatLng> = [];
21
+
22
+ for (let i = 0; i < numbers.length; i++) {
23
+ latLngs.push({
24
+ lat: parseFloat(numbers[i + 1]),
25
+ lng: parseFloat(numbers[i]),
26
+ } as LatLng);
27
+ i++;
28
+ }
29
+
30
+ return latLngs;
31
+ }
32
+
33
+ /**
34
+ * @param polygon An array of latitude and polygon that will be used to design an area in a map
35
+ * @param forUrl If true, the output string will be encoded as a URI so respecting the UTF-8 encoding
36
+ * */
37
+ export function encodePolygon(polygon: Array<LatLng>, forUrl = true): string {
38
+ const polygonArr: Array<any> = [];
39
+ polygon.forEach((p: LatLng) => {
40
+ polygonArr.push([p.lat, p.lng]);
41
+ });
42
+ const encodedPolygon = encode(polygonArr);
43
+ return forUrl ? encodeURIComponent(encodedPolygon) : encodedPolygon;
44
+ }
45
+
46
+ export function getMinMaxLatLng(polygon: Array<LatLng>): {
47
+ miny: number;
48
+ maxy: number;
49
+ minx: number;
50
+ maxx: number;
51
+ } {
52
+ const minmax = {
53
+ miny: polygon[0].lat,
54
+ maxy: polygon[0].lat,
55
+ minx: polygon[0].lng,
56
+ maxx: polygon[0].lng,
57
+ };
58
+ polygon.forEach((p: LatLng) => {
59
+ minmax.miny = Math.min(minmax.miny, p.lat);
60
+ minmax.maxy = Math.max(minmax.maxy, p.lat);
61
+ minmax.minx = Math.min(minmax.minx, p.lng);
62
+ minmax.maxx = Math.max(minmax.maxx, p.lng);
63
+ });
64
+ return minmax;
65
+ }
66
+
67
+ export function removeDuplicatePoints(latLngs: Array<LatLng>): Array<LatLng> {
68
+ if (latLngs.length <= 0) return [];
69
+
70
+ const uniqueCoordinates = new Set();
71
+ const unique = latLngs.filter((x) => {
72
+ const isDuplicate = uniqueCoordinates.has(x.lat + x.lng);
73
+ const coordinate = x.lat + x.lng;
74
+ uniqueCoordinates.add(coordinate);
75
+ return !isDuplicate;
76
+ });
77
+
78
+ return unique;
79
+ }
80
+
81
+ export function calcPolygonCenter(points: Array<LatLng>): LatLng {
82
+ let lat = 0;
83
+ let lng = 0;
84
+
85
+ for (let i = 0; i < points.length; i++) {
86
+ const point = points[i];
87
+
88
+ lat += point.lat;
89
+ lng += point.lng;
90
+ }
91
+
92
+ return { lat: lat / points.length, lng: lng / points.length } as LatLng;
93
+ }
94
+
95
+ export function validateMap(map: Leaflet_map): boolean {
96
+ const mapRange = window._mapRange || 10000;
97
+
98
+ if (map) {
99
+ const center = map.getShape()?.getCenter();
100
+ const points = map.getShapePoints();
101
+ if (points) {
102
+ for (let i = 0; i < points.length; i++) {
103
+ if (map.getDistance(points[i], center) > mapRange) return false;
104
+ }
105
+ }
106
+ return true;
107
+ }
108
+ return false;
109
+ }
110
+
111
+ export function getPolygonString(shapePoints: Array<LatLng>): string {
112
+ let polygonString = "POLYGON((";
113
+ shapePoints.forEach((point: LatLng) => {
114
+ polygonString += `${point.lng} ${point.lat}, `;
115
+ });
116
+ polygonString += `${shapePoints[0].lng} ${shapePoints[0].lat}))`;
117
+ return polygonString;
118
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Parse a localized number to a float.
3
+ * @param stringNumber - the localized number
4
+ * @param locale - [optional] the locale that the number is represented in. Omit this parameter to use the current locale.
5
+ */
6
+ export const parseLocaleNumber = (
7
+ stringNumber: string | number,
8
+ locale?: string
9
+ ): number | string => {
10
+ if (!locale) locale = navigator.language;
11
+
12
+ const thousandSeparator = Intl.NumberFormat(locale)
13
+ .format(1111)
14
+ .replace(/\p{Number}/gu, "");
15
+ const decimalSeparator = Intl.NumberFormat(locale)
16
+ .format(1.1)
17
+ .replace(/\p{Number}/gu, "");
18
+ const parsedNumber = parseFloat(
19
+ `${stringNumber}`
20
+ .replace(new RegExp("\\" + thousandSeparator, "g"), "")
21
+ .replace(new RegExp("\\" + decimalSeparator), ".")
22
+ );
23
+
24
+ /* In case the parsed number is NaN, we will return an empty string! */
25
+ if (isNaN(parsedNumber)) return "";
26
+
27
+ return parsedNumber;
28
+ };
29
+
30
+ export const formatLocaleNumber = (
31
+ numberToFormat?: number | string,
32
+ props?: { currency: boolean }
33
+ ): string | undefined | null => {
34
+ if (numberToFormat === undefined || numberToFormat === null) return;
35
+
36
+ numberToFormat = parseFloat(`${numberToFormat}`);
37
+
38
+ /* If the number to format is NaN, we won't return anything */
39
+ if (isNaN(numberToFormat)) return "";
40
+
41
+ const currencyOptions = {
42
+ style: "currency",
43
+ currency: "EUR",
44
+ };
45
+ const defaultOptions = {
46
+ maximumFractionDigits: 0,
47
+ };
48
+ let options = { ...defaultOptions };
49
+ if (props?.currency) options = { ...options, ...currencyOptions };
50
+
51
+ return new Intl.NumberFormat(navigator.language, {
52
+ ...options,
53
+ }).format(numberToFormat);
54
+ };
55
+
56
+ export function formatInteger(
57
+ value: number | undefined,
58
+ round: boolean = false
59
+ ): string {
60
+ if (value == null) return "";
61
+
62
+ return formatNumber(round ? Math.round(value) : Math.floor(value), 0);
63
+ }
64
+
65
+ export function formatNumber(
66
+ value: number | undefined,
67
+ digits?: number
68
+ ): string {
69
+ if (!value && value !== 0) return "";
70
+
71
+ return value.toLocaleString(
72
+ "it-IT", // usare una stringa tipo 'en-US' per sovrascrivere la lingua del browser
73
+ {
74
+ minimumFractionDigits: digits,
75
+ maximumFractionDigits: digits,
76
+ }
77
+ );
78
+ }
79
+
80
+ export function formatFloat(
81
+ value: number | undefined,
82
+ digits: number = 2
83
+ ): string {
84
+ return formatNumber(value, digits);
85
+ }
86
+
87
+ export const formatterNumberObj = {
88
+ formatFn: formatLocaleNumber,
89
+ unFormatFn: parseLocaleNumber,
90
+ };
@@ -0,0 +1,34 @@
1
+ export function shallowCopyObjectTo(
2
+ from: Record<string, any> | undefined,
3
+ to: Record<string, any>
4
+ ): void {
5
+ if (!from) return;
6
+
7
+ for (const k in from) {
8
+ to[k] = from[k];
9
+ }
10
+ }
11
+
12
+ export function isEmptyObject(obj: any): boolean {
13
+ return !obj || !Object.keys(obj).length;
14
+ }
15
+
16
+ /**
17
+ * Makes the deep copy of the input object.
18
+ * For performance purposes, if the values of the properties of the object to copy are all primitive types then we will use the spread operator (faster).
19
+ * Otherwise, to ensure the deep copy of nested objects and arrays, we will use JSON.parse and JSON.stringify (slower).
20
+ * */
21
+ export function deepCopy<T>(objToCopy: T): T | null {
22
+ if (!objToCopy) return null;
23
+
24
+ for (const key in objToCopy) {
25
+ const prop = objToCopy[key];
26
+ if (!prop) continue;
27
+
28
+ //Sebastian R.S: If the property value is a primitive type, then we will continue!
29
+ if (Array.isArray(prop) || Object.keys(prop).length > 0) {
30
+ return JSON.parse(JSON.stringify(objToCopy));
31
+ }
32
+ }
33
+ return { ...objToCopy };
34
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Observes if an element is visible in the viewport. Once it is visible, the listener is removed
3
+ * */
4
+ export function observeOnce(
5
+ selector: string,
6
+ fn: (Element: Node, IntersectionObserver: IntersectionObserver) => void,
7
+ options?: IntersectionObserverInit
8
+ ): void {
9
+ const elems = [].slice.call(document.querySelectorAll(selector));
10
+
11
+ const observer = new IntersectionObserver(
12
+ (
13
+ entries: Array<IntersectionObserverEntry>,
14
+ observer: IntersectionObserver
15
+ ) => {
16
+ for (let i = 0; i < entries.length; i++) {
17
+ const entry = entries[i];
18
+
19
+ if (entry.isIntersecting) {
20
+ const elem = entry.target;
21
+ fn(elem, observer);
22
+ observer.unobserve(elem);
23
+ }
24
+ }
25
+ },
26
+ options
27
+ );
28
+
29
+ elems.forEach((elem: HTMLElement) => {
30
+ observer.observe(elem);
31
+ });
32
+ }
@@ -0,0 +1,41 @@
1
+ export type PermissionStates = "granted" | "denied" | "prompt";
2
+ export type PermissionChangeEvent = CustomEvent<{
3
+ permissionState: PermissionStates;
4
+ }>;
5
+ export type NotificationPermissionChangeHandler = (
6
+ e: PermissionChangeEvent
7
+ ) => void | Promise<void>;
8
+
9
+ let permissionsListenerInit = false;
10
+
11
+ export const onNotificationsPermissionChange = (
12
+ cb: NotificationPermissionChangeHandler
13
+ ): void => {
14
+ // @ts-ignore
15
+ document.addEventListener("notification-permission-changed", cb);
16
+ };
17
+
18
+ /**
19
+ * Add an event listener which emits the event "notification-permission-changed" when the user changes the state of the notifications
20
+ * */
21
+ export const addPermissionStateListener = (): void => {
22
+ if (!navigator.permissions || !navigator.permissions.query) return;
23
+
24
+ //setting the listener ONCE
25
+ !permissionsListenerInit &&
26
+ navigator.permissions
27
+ .query({ name: "notifications" })
28
+ .then(function (permission) {
29
+ // Initial status is available at permission.state
30
+ permission.onchange = function (): void {
31
+ // Whenever there's a change, updated status is available at this.state
32
+ document.dispatchEvent(
33
+ new CustomEvent("notification-permission-changed", {
34
+ detail: { permissionState: this.state },
35
+ })
36
+ );
37
+ };
38
+ });
39
+
40
+ permissionsListenerInit = true;
41
+ };
@@ -0,0 +1,99 @@
1
+ import type { RealEstateSearchBean } from "@wikicasa-dev/types";
2
+
3
+ import {
4
+ CONTRACT,
5
+ searchBeanMap,
6
+ searchBeanMapAgencyFilter,
7
+ } from "@wikicasa-dev/types";
8
+
9
+ declare global {
10
+ interface Window {
11
+ _auctionLabel: string;
12
+ _rentLabel: string;
13
+ _saleLabel: string;
14
+ }
15
+ }
16
+
17
+ export function buildURL(
18
+ cityURL: string,
19
+ listingTypology: string,
20
+ contractType: number | undefined | null,
21
+ zone?: string | null,
22
+ seoFilter?: string | null,
23
+ agencyAndPlace?: string,
24
+ district?: string | null
25
+ ): string {
26
+ let URL = "/";
27
+
28
+ if (contractType) {
29
+ URL +=
30
+ (contractType == CONTRACT.AUCTION
31
+ ? window["_auctionLabel"]
32
+ : contractType == CONTRACT.RENT
33
+ ? window["_rentLabel"]
34
+ : window["_saleLabel"]) + "-";
35
+ }
36
+
37
+ URL += `${listingTypology}/`;
38
+
39
+ if (agencyAndPlace) URL += `${agencyAndPlace}/`;
40
+
41
+ if (cityURL) URL += `${cityURL.replace(/^-+|-+$/g, "")}/`;
42
+
43
+ if (zone) {
44
+ URL += `${zone.replace(/^_+|_+$/g, "")}/`;
45
+ }
46
+
47
+ if (!zone && district) {
48
+ URL += `${district.replace(/^_+|_+$/g, "")}/`;
49
+ }
50
+
51
+ if (seoFilter) {
52
+ URL += `${seoFilter.replace(/^_+|_+$/g, "")}/`;
53
+ }
54
+ return URL;
55
+ }
56
+
57
+ export function buildParams(searchBean: RealEstateSearchBean): string {
58
+ const params = Object.keys(searchBeanMap)
59
+ .map((key) => {
60
+ if (searchBean[key]) {
61
+ return (
62
+ encodeURIComponent(searchBeanMap[key]) +
63
+ "=" +
64
+ encodeURIComponent(searchBean[key])
65
+ );
66
+ } else return null;
67
+ })
68
+ .filter((param) => param !== null);
69
+
70
+ return params.length ? `?${params.join("&")}` : "";
71
+ }
72
+
73
+ export function buildParamsForAgency(searchBean: RealEstateSearchBean): string {
74
+ const params = Object.keys(searchBeanMapAgencyFilter)
75
+ .map((key) => {
76
+ if (searchBean[key]) {
77
+ if (Array.isArray(searchBean[key])) {
78
+ const arr = searchBean[key];
79
+ const nameField = searchBeanMapAgencyFilter[key];
80
+ let strToReturn = "";
81
+ for (let i = 0; i < arr.length; i++) {
82
+ strToReturn +=
83
+ encodeURIComponent(nameField) + "=" + encodeURIComponent(arr[i]);
84
+ strToReturn += i < arr.length - 1 ? "&" : "";
85
+ }
86
+ return strToReturn;
87
+ } else {
88
+ return (
89
+ encodeURIComponent(searchBeanMapAgencyFilter[key]) +
90
+ "=" +
91
+ encodeURIComponent(searchBean[key])
92
+ );
93
+ }
94
+ } else return null;
95
+ })
96
+ .filter((param) => param !== null);
97
+
98
+ return params.length ? `?${params.join("&")}` : "";
99
+ }
@@ -0,0 +1,20 @@
1
+ import axios from "axios";
2
+
3
+ import type { RequestGeneric } from "@wikicasa-dev/types";
4
+
5
+ export function sendRequestGeneric(rg: RequestGeneric): Promise<unknown> {
6
+ return new Promise(
7
+ (
8
+ resolve: (...args: Array<unknown>) => void,
9
+ reject: (error: Error) => void
10
+ ) =>
11
+ axios
12
+ .post("/rest/request/addRequestGenericValuation", rg, {
13
+ headers: { "Content-Type": "application/json", dataType: "json" },
14
+ })
15
+ .then(() => {
16
+ resolve();
17
+ })
18
+ .catch((error: any) => reject(error))
19
+ );
20
+ }