diff --git a/application/Geocoding/GeocodingController.php b/application/Geocoding/GeocodingController.php new file mode 100644 index 000000000..a434901c1 --- /dev/null +++ b/application/Geocoding/GeocodingController.php @@ -0,0 +1,48 @@ +needlogin = true; + $me = new User(); + $me->loadMe(); + $this->me = $me; + } + + protected function autocompleteAction() { + $search = urlencode($this->request->q); + $url = TT_GEOCODING_API_URL . "?address={$search}&key=" . TT_GEOCODING_API_SECRET . "®ion=at&language=de&components=country:AT"; + + if (!$response = @file_get_contents($url)) { + self::returnJson([]); + return; + } + + $data = json_decode($response, true); + var_dump($data); // Debugging line, can be removed in production + if ($data['status'] !== 'OK' || empty($data['results'])) { + self::returnJson([]); + return; + } + + $out = []; + foreach ($data['results'] as $entry) { + $hasHouseNumber = false; + foreach ($entry['address_components'] as $component) { + if (in_array('street_number', $component['types'])) { + $hasHouseNumber = true; + break; + } + } + + $text = $entry['formatted_address']; + $value = "{$entry['geometry']['location']['lat']},{$entry['geometry']['location']['lng']}" . ($hasHouseNumber ? '' : ', area'); + + $out[$text] = ['value' => $value, 'text' => $text]; + } + + self::returnJson(array_values($out)); + } + + +} \ No newline at end of file diff --git a/public/js/pages/PreorderRimoTypeMap/PreorderRimoTypeMap.js b/public/js/pages/PreorderRimoTypeMap/PreorderRimoTypeMap.js index b697ab26c..a628484a5 100644 --- a/public/js/pages/PreorderRimoTypeMap/PreorderRimoTypeMap.js +++ b/public/js/pages/PreorderRimoTypeMap/PreorderRimoTypeMap.js @@ -21,6 +21,7 @@ Vue.component('PreorderRimoTypeMap', { showFaultsModal: false, logoControlAdded: false, userIdToNameMap: new Map(), + editingFault: null, // Temporary state for the fault being edited faultReasons: [ { value: 'building_type', text: 'Gebäudetyp ist falsch' }, { value: 'home_count', text: 'Anzahl der Wohneinheiten ist falsch' }, @@ -112,12 +113,12 @@ Vue.component('PreorderRimoTypeMap', { } const storedShowFcps = localStorage.getItem('rimoMapShowFcps'); this.showFcps = storedShowFcps !== null ? JSON.parse(storedShowFcps) : true; - window.updateMapFault = this.handleFaultUpdate.bind(this); - window.saveMapFaults = this.saveFaults.bind(this); + window.updateEditingFault = this.updateTempFault.bind(this); + window.saveEditingFault = this.saveFaults.bind(this); }, beforeDestroy() { - delete window.updateMapFault; - delete window.saveMapFaults; + delete window.updateEditingFault; + delete window.saveEditingFault; }, methods: { addLogoToMap() { @@ -263,7 +264,7 @@ Vue.component('PreorderRimoTypeMap', { const rimoType = this.getNormalizedRimoType(group.rimo_type); const markerIcon = this.getMarkerIcon(rimoType); const fault = this.faults[group.hausnummer_id]; - const hasFault = fault && !fault.done; + const hasFault = fault && !fault.done && (fault.reasons.length > 0 || (fault.other && fault.other.trim() !== '')); let tooltipInnerClass = ''; if (rimoType !== 'greenfield' && group.wohneinheit_count > 0 && group.wohneinheit_count === group.preorder_count) @@ -330,11 +331,11 @@ Vue.component('PreorderRimoTypeMap', { const formInputs = this.faultReasons.map(reason => { const isChecked = faultData.reasons.includes(reason.value); const otherInput = (reason.value === 'other') ? - `` : + `` : ''; return ` ${otherInput}`; @@ -342,15 +343,20 @@ Vue.component('PreorderRimoTypeMap', { return `
Fehler melden/bearbeiten:
${formInputs} - `; + `; }, generateBuildingPopupHtml(itemGroup) { - const faultData = this.faults[itemGroup.hausnummer_id] || { reasons: [], other: '' }; + const currentFault = this.faults[itemGroup.hausnummer_id] || { reasons: [], other: '', done: false }; + this.editingFault = { + hausnummerId: itemGroup.hausnummer_id, + data: JSON.parse(JSON.stringify(currentFault)) + }; + const detailsHtml = this._generateBuildingDetailsHtml(itemGroup); - const faultFormHtml = this._generateBuildingFaultFormHtml(itemGroup, faultData); - const faultDisplayHtml = faultData.done ? - `
Dieser Fehler wurde von ${this.userIdToNameMap.get(String(faultData.done_by)) || `User #${faultData.done_by}`} am ${new Date(faultData.done_at).toLocaleDateString()} als erledigt markiert.
` : - this._generateBuildingFaultDisplayHtml(faultData); + const faultFormHtml = this._generateBuildingFaultFormHtml(itemGroup, this.editingFault.data); + const faultDisplayHtml = this.editingFault.data.done ? + `
Dieser Fehler wurde von ${this.userIdToNameMap.get(String(this.editingFault.data.done_by)) || `User #${this.editingFault.data.done_by}`} am ${new Date(this.editingFault.data.done_at).toLocaleDateString()} als erledigt markiert.
` : + this._generateBuildingFaultDisplayHtml(this.editingFault.data); return `
${detailsHtml} @@ -359,36 +365,49 @@ Vue.component('PreorderRimoTypeMap', {
${faultFormHtml}
`; }, - handleFaultUpdate(hausnummerId, reason, value, from_mark_as_done = false) { - if (!this.faults[hausnummerId]) - this.$set(this.faults, hausnummerId, { reasons: [], other: '', done: false }); - else if (this.faults[hausnummerId].done && !from_mark_as_done) - this.$set(this.faults, hausnummerId, { reasons: [], other: '', done: false }); + updateTempFault(reason, value) { + if (!this.editingFault) return; + if (this.editingFault.data.done) { + this.editingFault.data.done = false; + this.editingFault.data.done_by = null; + this.editingFault.data.done_at = null; + } - const fault = this.faults[hausnummerId]; + const fault = this.editingFault.data; if (reason === 'other_text') { fault.other = value; - } else if (reason) { + } else { // It's a checkbox change const index = fault.reasons.indexOf(reason); - if (value && index === -1) fault.reasons.push(reason); - else if (!value && index > -1) fault.reasons.splice(index, 1); - - const popup = this.$refs.ttMap?.map?._popup; - if (popup?.isOpen()) { - const otherTextarea = popup.getElement().querySelector('.fault-other-textarea'); - if (otherTextarea) otherTextarea.classList.toggle('hidden', !fault.reasons.includes('other')); + if (value && index === -1) { // checked + fault.reasons.push(reason); + } else if (!value && index > -1) { // unchecked + fault.reasons.splice(index, 1); } - } - const markerInstance = this.$refs.ttMap.markerLayer.getLayers().find(m => m.tt_hausnummerId == hausnummerId); - if (markerInstance?.getElement) { - const hasOpenFault = fault && !fault.done && (fault.reasons.length > 0 || fault.other); - markerInstance.getElement().classList.toggle('marker-has-fault', hasOpenFault); + if (reason === 'other') { + const popup = this.$refs.ttMap?.map?._popup; + if (popup?.isOpen()) { + const otherTextarea = popup.getElement().querySelector('.fault-other-textarea'); + if (otherTextarea) { + const hasOther = fault.reasons.includes('other'); + otherTextarea.classList.toggle('hidden', !hasOther); + if (!hasOther) { + otherTextarea.value = ''; + fault.other = ''; + } + } + } + } } }, async saveFaults() { + if (!this.editingFault) return; + const { hausnummerId, data } = this.editingFault; + + this.$set(this.faults, hausnummerId, data); + const response = await axios.post(`${window.TT_CONFIG.BASE_PATH}/Preorder/RimoTypeMapSaveFaults`, { campaignId: this.selectedCampaign, faults: this.faults @@ -396,9 +415,11 @@ Vue.component('PreorderRimoTypeMap', { if (response.data.success) { window.notify('success', 'Fehlerbericht gespeichert.'); this.$refs.ttMap?.map.closePopup(); + this.mapMarkers = this.processData(this.rawRimoData); } else { window.notify('error', 'Fehlerbericht konnte nicht gespeichert werden.'); } + this.editingFault = null; }, async markFaultAsDone(hausnummerId) { if (!hausnummerId || !this.faults[hausnummerId]) return; @@ -411,7 +432,6 @@ Vue.component('PreorderRimoTypeMap', { }); await this.saveFaults(); - this.handleFaultUpdate(hausnummerId, null, null, true); }, zoomToFaultMarker(hausnummerId) { const map = this.$refs.ttMap?.map; @@ -475,28 +495,28 @@ Vue.component('PreorderRimoTypeMap', { >
-
Filter:
- -
- - +
Filter:
+ +
+ +