151 lines
4.6 KiB
JavaScript
151 lines
4.6 KiB
JavaScript
/** @odoo-module **/
|
|
|
|
import { Component, onMounted, onWillUnmount, useRef, useState } from "@odoo/owl";
|
|
import { registry } from "@web/core/registry";
|
|
import { standardFieldProps } from "@web/views/fields/standard_field_props";
|
|
import { rpc } from "@web/core/network/rpc";
|
|
|
|
/**
|
|
* Google Places Autocomplete widget for the address field.
|
|
* Automatically geocodes the selected place and updates lat/lng on the record.
|
|
*/
|
|
export class FusionClockPlacesAutocomplete extends Component {
|
|
static template = "fusion_clock.PlacesAutocomplete";
|
|
static props = { ...standardFieldProps };
|
|
|
|
setup() {
|
|
this.inputRef = useRef("addressInput");
|
|
this.autocomplete = null;
|
|
this._apiReady = false;
|
|
|
|
this.state = useState({
|
|
value: this.props.record.data[this.props.name] || "",
|
|
});
|
|
|
|
onMounted(() => this._init());
|
|
onWillUnmount(() => this._cleanup());
|
|
}
|
|
|
|
get isReadonly() {
|
|
return this.props.readonly;
|
|
}
|
|
|
|
async _getApiKey() {
|
|
try {
|
|
return await rpc("/web/dataset/call_kw", {
|
|
model: "ir.config_parameter",
|
|
method: "get_param",
|
|
args: ["fusion_clock.google_maps_api_key", ""],
|
|
kwargs: {},
|
|
}) || "";
|
|
} catch (e) {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
async _waitForGoogleMaps() {
|
|
if (window.google && window.google.maps && window.google.maps.places) {
|
|
return true;
|
|
}
|
|
return new Promise((resolve) => {
|
|
let attempts = 0;
|
|
const check = setInterval(() => {
|
|
attempts++;
|
|
if (window.google && window.google.maps && window.google.maps.places) {
|
|
clearInterval(check);
|
|
resolve(true);
|
|
}
|
|
if (attempts > 50) {
|
|
clearInterval(check);
|
|
resolve(false);
|
|
}
|
|
}, 100);
|
|
});
|
|
}
|
|
|
|
async _loadGoogleMaps(apiKey) {
|
|
if (window.google && window.google.maps) return;
|
|
|
|
if (document.querySelector('script[src*="maps.googleapis.com"]')) {
|
|
await this._waitForGoogleMaps();
|
|
return;
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const script = document.createElement("script");
|
|
script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places&callback=__fclkPlacesInit`;
|
|
script.async = true;
|
|
script.defer = true;
|
|
window.__fclkPlacesInit = () => {
|
|
delete window.__fclkPlacesInit;
|
|
resolve();
|
|
};
|
|
script.onerror = () => reject(new Error("Failed to load Google Maps"));
|
|
document.head.appendChild(script);
|
|
});
|
|
}
|
|
|
|
async _init() {
|
|
if (this.isReadonly) return;
|
|
|
|
const apiKey = await this._getApiKey();
|
|
if (!apiKey) return;
|
|
|
|
try {
|
|
await this._loadGoogleMaps(apiKey);
|
|
} catch (e) {
|
|
return;
|
|
}
|
|
|
|
await this._waitForGoogleMaps();
|
|
|
|
if (!this.inputRef.el || !window.google || !window.google.maps.places) return;
|
|
|
|
this.autocomplete = new google.maps.places.Autocomplete(this.inputRef.el, {
|
|
types: ["geocode", "establishment"],
|
|
fields: ["formatted_address", "geometry", "name"],
|
|
});
|
|
|
|
this.autocomplete.addListener("place_changed", () => {
|
|
const place = this.autocomplete.getPlace();
|
|
if (!place || !place.geometry) return;
|
|
|
|
const lat = place.geometry.location.lat();
|
|
const lng = place.geometry.location.lng();
|
|
const address = place.formatted_address || place.name || "";
|
|
|
|
this.state.value = address;
|
|
this.props.record.update({
|
|
[this.props.name]: address,
|
|
latitude: Math.round(lat * 10000000) / 10000000,
|
|
longitude: Math.round(lng * 10000000) / 10000000,
|
|
});
|
|
});
|
|
}
|
|
|
|
onInput(ev) {
|
|
this.state.value = ev.target.value;
|
|
}
|
|
|
|
onChange(ev) {
|
|
this.props.record.update({ [this.props.name]: ev.target.value });
|
|
}
|
|
|
|
_cleanup() {
|
|
if (this.autocomplete) {
|
|
google.maps.event.clearInstanceListeners(this.autocomplete);
|
|
this.autocomplete = null;
|
|
}
|
|
|
|
const containers = document.querySelectorAll(".pac-container");
|
|
containers.forEach((c) => c.remove());
|
|
}
|
|
}
|
|
|
|
FusionClockPlacesAutocomplete.template = "fusion_clock.PlacesAutocomplete";
|
|
|
|
registry.category("fields").add("fclk_places_autocomplete", {
|
|
component: FusionClockPlacesAutocomplete,
|
|
supportedTypes: ["char"],
|
|
});
|