@wikicasa-dev/utilities 0.1.0 → 0.1.2
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.
- package/dist/index.d.ts +1 -0
- package/dist/utilities.cjs +5 -0
- package/dist/{utilities.umd.cjs → utilities.iife.js} +4 -4
- package/dist/{utilities.js → utilities.mjs} +57 -51
- package/dist/utils/DateUtils.d.ts +1 -0
- package/package.json +10 -7
- package/src/custom/constants.ts +3 -0
- package/src/custom/icons.ts +63 -0
- package/src/custom/leaflet_map.ts +946 -0
- package/src/index.ts +173 -0
- package/src/services/agencyAPI.ts +105 -0
- package/src/services/geographyAPI.ts +129 -0
- package/src/services/insightsAPI.ts +20 -0
- package/src/services/mailAPI.ts +89 -0
- package/src/services/placesAPI.ts +72 -0
- package/src/services/portfolioCustomerAPI.ts +16 -0
- package/src/services/publicUserAPI.ts +216 -0
- package/src/services/realEstateAPI.ts +133 -0
- package/src/services/requestAPI.ts +40 -0
- package/src/services/servicesUtils.ts +27 -0
- package/src/services/statisticsAPI.ts +84 -0
- package/src/services/valuationAPI.ts +45 -0
- package/src/services/wikicasaPro.ts +25 -0
- package/src/utils/AppRedirectUtils.ts +26 -0
- package/src/utils/ArrayUtils.ts +2 -0
- package/src/utils/ColorUtils.ts +11 -0
- package/src/utils/CookieUtils.ts +43 -0
- package/src/utils/CurrencyUtils.ts +18 -0
- package/src/utils/DOMUtils.ts +28 -0
- package/src/utils/DateUtils.ts +9 -0
- package/src/utils/DeviceDetectionUtils.ts +17 -0
- package/src/utils/EmailUtils.ts +45 -0
- package/src/utils/FavoriteUtils.ts +19 -0
- package/src/utils/FunctionUtils.ts +29 -0
- package/src/utils/GAEvents.ts +414 -0
- package/src/utils/GAutocompleteUtils.ts +70 -0
- package/src/utils/GenericUtils.ts +37 -0
- package/src/utils/LazyLoadingBg.ts +18 -0
- package/src/utils/MapUtils.ts +118 -0
- package/src/utils/NumberUtils.ts +90 -0
- package/src/utils/ObjectUtils.ts +34 -0
- package/src/utils/ObserverUtils.ts +32 -0
- package/src/utils/PermissionUtils.ts +41 -0
- package/src/utils/RESB_UrlBuilder.ts +99 -0
- package/src/utils/RequestUtils.ts +20 -0
- package/src/utils/StringUtils.ts +67 -0
- package/src/utils/URLBuilderUtils.ts +21 -0
- package/src/utils/URLPagesFactory.ts +20 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +38 -0
- package/vite.config.ts +42 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Nullable } from "@wikicasa-dev/types";
|
|
2
|
+
|
|
3
|
+
export const getSingleElement = (selector: string): HTMLElement => {
|
|
4
|
+
const el = document.querySelector(selector) as HTMLElement;
|
|
5
|
+
if (!el) throw new Error(`No element found with the id: ${selector}`);
|
|
6
|
+
return el;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const emptyElem = (selectorOrElem: string | Element): void => {
|
|
10
|
+
if (typeof selectorOrElem === "string")
|
|
11
|
+
getSingleElement(selectorOrElem).textContent = "";
|
|
12
|
+
else selectorOrElem.textContent = "";
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const showElem = (
|
|
16
|
+
elem: Nullable<HTMLElement>,
|
|
17
|
+
displayValue: "block" | "d-flex" = "block"
|
|
18
|
+
): void => {
|
|
19
|
+
if (!elem) return;
|
|
20
|
+
|
|
21
|
+
elem.style.display = displayValue;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const hideElem = (elem: Nullable<HTMLElement>): void => {
|
|
25
|
+
if (!elem) return;
|
|
26
|
+
|
|
27
|
+
elem.style.display = "none";
|
|
28
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function formatDate(date: Date, display: boolean = false): string {
|
|
2
|
+
const day = date.getDate();
|
|
3
|
+
const month = date.getMonth() + 1;
|
|
4
|
+
const year = date.getFullYear();
|
|
5
|
+
|
|
6
|
+
return display
|
|
7
|
+
? `${("0" + day).slice(-2)}-${("0" + month).slice(-2)}-${year}`
|
|
8
|
+
: `${year}-${("0" + month).slice(-2)}-${("0" + day).slice(-2)}`;
|
|
9
|
+
}
|
|
@@ -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
|
+
export function debounce<T extends Function, TReturn>(
|
|
14
|
+
timeout: { id?: ReturnType<typeof setTimeout>; delay: number },
|
|
15
|
+
func: T
|
|
16
|
+
): (...args: any) => Promise<TReturn> {
|
|
17
|
+
return (...args: any): Promise<TReturn> =>
|
|
18
|
+
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,414 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Nullable,
|
|
3
|
+
GA3Props,
|
|
4
|
+
GA4Props,
|
|
5
|
+
GAEvent,
|
|
6
|
+
GaPhoneShowPayload,
|
|
7
|
+
GaRequestPayload,
|
|
8
|
+
GaValuationPayload,
|
|
9
|
+
GaValuationSellingPayload,
|
|
10
|
+
GenericPayload,
|
|
11
|
+
ValuationEventObject,
|
|
12
|
+
} from "@wikicasa-dev/types";
|
|
13
|
+
|
|
14
|
+
const createBaseGAEvent = (
|
|
15
|
+
GA3_props: Nullable<GA3Props>,
|
|
16
|
+
GA4_props: GA4Props
|
|
17
|
+
): Partial<GA3Props> & GA4Props => {
|
|
18
|
+
return GA3_props ? { ...GA3_props, ...GA4_props } : { ...GA4_props };
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const sendValuationGAEvent = (payload: GaValuationPayload): void => {
|
|
22
|
+
const eventObject: ValuationEventObject = {
|
|
23
|
+
event: "GAevent",
|
|
24
|
+
eventCategory: "Valutazione immobile",
|
|
25
|
+
eventAction: payload.eventAction,
|
|
26
|
+
eventLabel: "Pagina valutazione",
|
|
27
|
+
//GA4
|
|
28
|
+
event_name:
|
|
29
|
+
payload.eventAction === "Share"
|
|
30
|
+
? "valuation_share"
|
|
31
|
+
: "valuation_share_modal",
|
|
32
|
+
event_location: "Valutazione",
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
if (payload.social) eventObject.social = payload.social;
|
|
36
|
+
|
|
37
|
+
//@ts-ignore
|
|
38
|
+
window["dataLayer"].push(eventObject);
|
|
39
|
+
};
|
|
40
|
+
const sendRequestGAEvent = (data: GaRequestPayload): void => {
|
|
41
|
+
//@ts-ignore
|
|
42
|
+
window["dataLayer"].push({
|
|
43
|
+
event: "GAevent",
|
|
44
|
+
eventCategory: data.id ? "Richiesta specifica" : "Richiesta agenzia",
|
|
45
|
+
eventAction: "Invio richiesta",
|
|
46
|
+
// eslint-disable-next-line max-len
|
|
47
|
+
eventLabel:
|
|
48
|
+
(data.franchise
|
|
49
|
+
? `${data.franchise} / AG_${data.agencyId}`
|
|
50
|
+
: `AG_${data.agencyId}`) +
|
|
51
|
+
(data.id
|
|
52
|
+
? ` / WK_${data.id} (${data.pageName}: ${
|
|
53
|
+
data.sale ? "vendita" : "affitto"
|
|
54
|
+
} / ${data.premium ? "premium" : data.lite ? "lite" : "free"})`
|
|
55
|
+
: ` (${data.pageName}: ${
|
|
56
|
+
data.premium ? "premium" : data.lite ? "lite" : "free"
|
|
57
|
+
})`),
|
|
58
|
+
franchise: data.franchise ? data.franchise : undefined,
|
|
59
|
+
agent_id: data.agentId ? `${data.agentId}` : undefined,
|
|
60
|
+
agent_email: data.agentEmail,
|
|
61
|
+
product_price: data.productPrice,
|
|
62
|
+
email: data.email,
|
|
63
|
+
//GA4
|
|
64
|
+
event_name: data.id ? "specific_request_lead" : "generic_request_lead",
|
|
65
|
+
event_location: `${data.pageName}`,
|
|
66
|
+
real_estate_id: data.id,
|
|
67
|
+
product_id: `WK_${data.id}`,
|
|
68
|
+
contract_type: data.id
|
|
69
|
+
? data.auction
|
|
70
|
+
? "auction"
|
|
71
|
+
: data.rent
|
|
72
|
+
? "rent"
|
|
73
|
+
: "sale"
|
|
74
|
+
: undefined,
|
|
75
|
+
price: data.price,
|
|
76
|
+
typology_name: data.typologyName,
|
|
77
|
+
agency_id: data.agencyId,
|
|
78
|
+
agency_name: data.agencyName,
|
|
79
|
+
franchise_id: data.franchise_id,
|
|
80
|
+
franchise_name: data.franchise_name,
|
|
81
|
+
subscription_type: data.premium ? "premium" : data.lite ? "lite" : "free",
|
|
82
|
+
premium: data.premium,
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
const sendMortgageGAEvent = (): void => {
|
|
86
|
+
//@ts-ignore
|
|
87
|
+
window["dataLayer"].push({
|
|
88
|
+
event: "GAevent",
|
|
89
|
+
eventCategory: "Preventivo Mutuo",
|
|
90
|
+
eventAction: "Invio richiesta",
|
|
91
|
+
eventLabel: "Popup - Richiesta specifica",
|
|
92
|
+
//GA4
|
|
93
|
+
event_name: "mortgage_lead",
|
|
94
|
+
event_location: "Modale Richiesta Specifica",
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
const sendMailAlertSaveGAEvent = (): void => {
|
|
98
|
+
//@ts-ignore
|
|
99
|
+
window["dataLayer"].push({
|
|
100
|
+
event: "GAevent",
|
|
101
|
+
eventCategory: "Mail alert",
|
|
102
|
+
eventAction: "Ricerca salvata",
|
|
103
|
+
eventLabel: "Popup - Richiesta specifica",
|
|
104
|
+
//GA4
|
|
105
|
+
event_name: "mail_alert_save",
|
|
106
|
+
event_location: "Modale Richiesta Specifica",
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
const sendGenericRequestLead = (): void => {
|
|
110
|
+
//@ts-ignore
|
|
111
|
+
window["dataLayer"].push({
|
|
112
|
+
event: "GAevent",
|
|
113
|
+
eventCategory: "Richiesta generica",
|
|
114
|
+
eventAction: "Invio richiesta",
|
|
115
|
+
eventLabel: "Popup - Richiesta specifica",
|
|
116
|
+
//GA4
|
|
117
|
+
event_name: "generic_request_lead",
|
|
118
|
+
event_location: "Modale Richiesta Specifica",
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
const sendNewsletterSubscribeGAEvent = (): void => {
|
|
122
|
+
//@ts-ignore
|
|
123
|
+
window["dataLayer"].push({
|
|
124
|
+
event: "GAevent",
|
|
125
|
+
eventCategory: "Newsletter",
|
|
126
|
+
eventAction: "Iscrizione",
|
|
127
|
+
eventLabel: "Popup - Richiesta specifica",
|
|
128
|
+
//GA4
|
|
129
|
+
event_name: "newsletter_subscribe",
|
|
130
|
+
event_location: "Modale Richiesta Specifica",
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
const sendPhoneShowGAEvent = (agencyData: GaPhoneShowPayload): void => {
|
|
134
|
+
//@ts-ignore
|
|
135
|
+
window["dataLayer"].push({
|
|
136
|
+
event: "GAevent",
|
|
137
|
+
eventCategory: "Telefono",
|
|
138
|
+
eventAction: "Mostra telefono",
|
|
139
|
+
// eslint-disable-next-line max-len
|
|
140
|
+
eventLabel:
|
|
141
|
+
(agencyData.franchise
|
|
142
|
+
? `${agencyData.franchise} / AG_${agencyData.agencyId}`
|
|
143
|
+
: `AG_${agencyData.agencyId}`) +
|
|
144
|
+
// eslint-disable-next-line max-len
|
|
145
|
+
(agencyData.id
|
|
146
|
+
? ` / WK_${agencyData.id} (${agencyData.pageName}: ${
|
|
147
|
+
agencyData.sale ? "vendita" : "affitto"
|
|
148
|
+
} / ${
|
|
149
|
+
agencyData.premium ? "premium" : agencyData.lite ? "lite" : "free"
|
|
150
|
+
})`
|
|
151
|
+
: ` (${agencyData.pageName}: ${
|
|
152
|
+
agencyData.premium ? "premium" : agencyData.lite ? "lite" : "free"
|
|
153
|
+
})`),
|
|
154
|
+
franchise: agencyData.franchise ? agencyData.franchise : undefined,
|
|
155
|
+
product_id: agencyData.id ? `WK_${agencyData.id}` : undefined,
|
|
156
|
+
product_price: agencyData.product_price,
|
|
157
|
+
//GA4
|
|
158
|
+
event_name: "phone_show",
|
|
159
|
+
real_estate_id: `${agencyData.id}`,
|
|
160
|
+
contract_type: agencyData.auction
|
|
161
|
+
? "auction"
|
|
162
|
+
: agencyData.rent && !agencyData.sale
|
|
163
|
+
? "rent"
|
|
164
|
+
: "sale",
|
|
165
|
+
price: agencyData.price,
|
|
166
|
+
typology_name: agencyData.typologyName,
|
|
167
|
+
agency_id: agencyData.agencyId,
|
|
168
|
+
agency_name: agencyData?.agencyName,
|
|
169
|
+
franchise_id: agencyData.franchise ? agencyData.franchise_id : "",
|
|
170
|
+
franchise_name: agencyData.franchise,
|
|
171
|
+
premium: agencyData.premium,
|
|
172
|
+
subscription_type: agencyData.premium
|
|
173
|
+
? "premium"
|
|
174
|
+
: agencyData.lite
|
|
175
|
+
? "lite"
|
|
176
|
+
: "free",
|
|
177
|
+
event_location: agencyData.pageName,
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
const sendPublicUserLoginGAEvent = (): void => {
|
|
181
|
+
//@ts-ignore
|
|
182
|
+
window["dataLayer"].push({
|
|
183
|
+
event: "GAevent",
|
|
184
|
+
eventCategory: "Utenti pubblici",
|
|
185
|
+
eventAction: "Login",
|
|
186
|
+
eventLabel: "Modale Login",
|
|
187
|
+
//GA4
|
|
188
|
+
event_name: "login",
|
|
189
|
+
event_location: "login_modal",
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const sendNotificationOpenedGAEvent = (): void => {
|
|
194
|
+
const GAEventObj = createBaseGAEvent(
|
|
195
|
+
{
|
|
196
|
+
event: "GAevent",
|
|
197
|
+
eventCategory: "Mail alert",
|
|
198
|
+
eventAction: "Apertura notifica push",
|
|
199
|
+
eventLabel: "Notifica Push - Salva ricerca",
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
event: "GAevent",
|
|
203
|
+
event_name: "push_notification_opened",
|
|
204
|
+
event_location: "Notifica Push - Android_or_Web",
|
|
205
|
+
}
|
|
206
|
+
);
|
|
207
|
+
//@ts-ignore
|
|
208
|
+
window["dataLayer"].push({ event_location: "save_searches", ...GAEventObj });
|
|
209
|
+
};
|
|
210
|
+
const sendSignUpGAEvent = (): void => {
|
|
211
|
+
//@ts-ignore
|
|
212
|
+
window["dataLayer"].push(
|
|
213
|
+
createBaseGAEvent(
|
|
214
|
+
{
|
|
215
|
+
event: "GAevent",
|
|
216
|
+
eventCategory: "Utenti pubblici",
|
|
217
|
+
eventAction: "Registrazione",
|
|
218
|
+
eventLabel: "Modale registrazione",
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
event: "GAevent",
|
|
222
|
+
event_name: "public_user_sign_up",
|
|
223
|
+
event_location: "Modale Registrazione",
|
|
224
|
+
}
|
|
225
|
+
)
|
|
226
|
+
);
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const sendErrorRequestGAEvent = (): void => {
|
|
230
|
+
//@ts-ignore
|
|
231
|
+
window["dataLayer"].push({
|
|
232
|
+
event: "GAevent",
|
|
233
|
+
eventCategory: "Richiesta Specifica",
|
|
234
|
+
eventAction: "Errore Richiesta",
|
|
235
|
+
eventLabel: "Richiesta gia effettuata - 409",
|
|
236
|
+
//GA4
|
|
237
|
+
event_name: "specific_request_error",
|
|
238
|
+
event_location: "Modale Richiesta Specifica",
|
|
239
|
+
code_error: "request_already_made_409",
|
|
240
|
+
});
|
|
241
|
+
};
|
|
242
|
+
const sendPremiumInfoGAEvent = (): void => {
|
|
243
|
+
//@ts-ignore
|
|
244
|
+
window["dataLayer"].push(
|
|
245
|
+
createBaseGAEvent(
|
|
246
|
+
{
|
|
247
|
+
event: "GAevent",
|
|
248
|
+
eventCategory: "Premium",
|
|
249
|
+
eventAction: "Richiesta Informazioni",
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
event: "GAevent",
|
|
253
|
+
event_name: "premium_info",
|
|
254
|
+
event_location: "Pagina Premium",
|
|
255
|
+
}
|
|
256
|
+
)
|
|
257
|
+
);
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const sendValuationComplete = (): void => {
|
|
261
|
+
//@ts-ignore
|
|
262
|
+
window["dataLayer"].push(
|
|
263
|
+
createBaseGAEvent(
|
|
264
|
+
{
|
|
265
|
+
event: "GAevent",
|
|
266
|
+
eventCategory: "Valutazione immobile",
|
|
267
|
+
eventAction: "Invio richiesta",
|
|
268
|
+
eventLabel: "Pagina valutazione",
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
event: "GAevent",
|
|
272
|
+
event_name: "valuation_complete",
|
|
273
|
+
event_location: "Valutazione - Step 3",
|
|
274
|
+
}
|
|
275
|
+
)
|
|
276
|
+
);
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const sendValuationLead = (
|
|
280
|
+
sellingPayload: GaValuationSellingPayload = {
|
|
281
|
+
isSelling: false,
|
|
282
|
+
}
|
|
283
|
+
): void => {
|
|
284
|
+
//@ts-ignore
|
|
285
|
+
window["dataLayer"].push(
|
|
286
|
+
createBaseGAEvent(null, {
|
|
287
|
+
event: "GAevent",
|
|
288
|
+
event_name: "valuation_lead",
|
|
289
|
+
event_location: "Valutazione - Step 3",
|
|
290
|
+
valuation_type: sellingPayload.isSelling ? "selling" : "valuation",
|
|
291
|
+
})
|
|
292
|
+
);
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const sendDownloadPDF = (): void => {
|
|
296
|
+
//@ts-ignore
|
|
297
|
+
window["dataLayer"].push(
|
|
298
|
+
createBaseGAEvent(
|
|
299
|
+
{
|
|
300
|
+
event: "GAevent",
|
|
301
|
+
eventCategory: "Valutazione immobile",
|
|
302
|
+
eventAction: "Download PDF",
|
|
303
|
+
eventLabel: "Pagina valutazione",
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
event: "GAevent",
|
|
307
|
+
//GA4
|
|
308
|
+
event_name: "valuation_pdf_download",
|
|
309
|
+
event_location: "Valutazione",
|
|
310
|
+
}
|
|
311
|
+
)
|
|
312
|
+
);
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const sendRequestModalInteractionGAEvent = (props: {
|
|
316
|
+
pageName: string;
|
|
317
|
+
}): void => {
|
|
318
|
+
const gaEvent = createBaseGAEvent(null, {
|
|
319
|
+
event: "GAevent",
|
|
320
|
+
event_name: "specific_request_interaction",
|
|
321
|
+
event_location: props.pageName,
|
|
322
|
+
});
|
|
323
|
+
//@ts-ignore
|
|
324
|
+
window["dataLayer"].push(gaEvent);
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const copyAVMwidgetGAEvent = (): void => {
|
|
328
|
+
//@ts-ignore
|
|
329
|
+
window["dataLayer"].push(
|
|
330
|
+
createBaseGAEvent(
|
|
331
|
+
{
|
|
332
|
+
event: "GAevent",
|
|
333
|
+
eventCategory: "Widget AVM",
|
|
334
|
+
eventAction: "Copia Widget AVM",
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
event: "GAevent",
|
|
338
|
+
event_name: "copy_avm_widget",
|
|
339
|
+
event_location: "Pagina Widget AVM",
|
|
340
|
+
}
|
|
341
|
+
)
|
|
342
|
+
);
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
const copyTrendWidgetGAEvent = (): void => {
|
|
346
|
+
//@ts-ignore
|
|
347
|
+
window["dataLayer"].push(
|
|
348
|
+
createBaseGAEvent(
|
|
349
|
+
{
|
|
350
|
+
event: "GAevent",
|
|
351
|
+
eventCategory: "Widget Quotazioni",
|
|
352
|
+
eventAction: "Copia Widget Quotazioni",
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
event: "GAevent",
|
|
356
|
+
event_name: "copy_trend_widget",
|
|
357
|
+
event_location: "Pagina Widget Quotazioni",
|
|
358
|
+
}
|
|
359
|
+
)
|
|
360
|
+
);
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
const sendAVMwidgetRequest = (): void => {
|
|
364
|
+
//@ts-ignore
|
|
365
|
+
window["dataLayer"].push(
|
|
366
|
+
createBaseGAEvent(
|
|
367
|
+
{
|
|
368
|
+
event: "GAevent",
|
|
369
|
+
eventCategory: "Widget AVM",
|
|
370
|
+
eventAction: "Invio Richiesta Widget AVM",
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
event: "GAevent",
|
|
374
|
+
event_name: "send_request_avm_widget",
|
|
375
|
+
event_location: "Pagina Widget AVM",
|
|
376
|
+
}
|
|
377
|
+
)
|
|
378
|
+
);
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
const GAEventHandler: Record<GAEvent, (...args: any[]) => void> = {
|
|
382
|
+
valuation: sendValuationGAEvent,
|
|
383
|
+
request: sendRequestGAEvent,
|
|
384
|
+
mortgage: sendMortgageGAEvent,
|
|
385
|
+
mailAlertSave: sendMailAlertSaveGAEvent,
|
|
386
|
+
generic_request_lead: sendGenericRequestLead,
|
|
387
|
+
newsletter_subscribe: sendNewsletterSubscribeGAEvent,
|
|
388
|
+
phone_show: sendPhoneShowGAEvent,
|
|
389
|
+
public_user_login: sendPublicUserLoginGAEvent,
|
|
390
|
+
pushNotificationOpened: sendNotificationOpenedGAEvent,
|
|
391
|
+
public_user_sign_up: sendSignUpGAEvent,
|
|
392
|
+
premium_info: sendPremiumInfoGAEvent,
|
|
393
|
+
valuation_complete: sendValuationComplete,
|
|
394
|
+
valuation_lead: sendValuationLead,
|
|
395
|
+
valuation_pdf_download: sendDownloadPDF,
|
|
396
|
+
error_request_409: sendErrorRequestGAEvent,
|
|
397
|
+
specific_request_interaction: sendRequestModalInteractionGAEvent,
|
|
398
|
+
copy_avm_widget: copyAVMwidgetGAEvent,
|
|
399
|
+
copy_trend_widget: copyTrendWidgetGAEvent,
|
|
400
|
+
send_avm_widget_request: sendAVMwidgetRequest,
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
// eslint-disable-next-line max-len
|
|
404
|
+
export function sendGAEvent<
|
|
405
|
+
T extends
|
|
406
|
+
| GaValuationPayload
|
|
407
|
+
| GaRequestPayload
|
|
408
|
+
| GaPhoneShowPayload
|
|
409
|
+
| GenericPayload
|
|
410
|
+
| GaValuationSellingPayload
|
|
411
|
+
>(GAEvent: GAEvent, payload?: T): void {
|
|
412
|
+
const handler = GAEventHandler[GAEvent];
|
|
413
|
+
payload ? handler(payload) : handler();
|
|
414
|
+
}
|
|
@@ -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
|
+
});
|