1- import { Component , ChangeDetectionStrategy , input , output } from '@angular/core' ;
1+ import { Component , ChangeDetectionStrategy , input , output , effect , ElementRef , viewChild } from '@angular/core' ;
22import { CommonModule } from '@angular/common' ;
33import { FormsModule } from '@angular/forms' ;
44import { AdminLocation , OwnerInfo } from '@shared/models' ;
5+ import * as L from 'leaflet' ;
56
67@Component ( {
78 selector : 'app-business-profile' ,
@@ -66,16 +67,16 @@ import { AdminLocation, OwnerInfo } from '@shared/models';
6667 </div>
6768 </div>
6869 </div>
69- <div>
70- <label class="block text-sm font-semibold text-gray-700 mb-2 uppercase tracking-wider" i18n="@@settingsLabelMap">Map Preview</label >
71- <div class="h-[235px] w-full rounded-2xl bg -gray-100 border border-gray-200 overflow-hidden relative group" >
72- <img alt="Map Preview " class="w-full h-full object-cover opacity-60 grayscale group-hover:grayscale-0 transition-all duration-500" src="https://lh3.googleusercontent.com/aida-public/AB6AXuDonmZQfuLMnod8C7wis0atCzWNP6hXp4m4AoTUkoIuPmARE_RPVbF8IOpf0C5vL9JCeOUxLeEbrkKIbexjZNjWi7N0mOGT4vh5gfIwVQ6W6t_y1RrbJ8mQdVkZDKa3iIPYPOCAcNuCyqCDj1BJlO-SzpspJY1_K_8iJC8huctLGH8gw04zghpbK-aLIeK0eF2OdSo5Cyx8uG_rZsuVHV606R48a5A23KKY9m5fok_i6f00f_floYzSSA3W0cuUMIGxWr-KW4RYNyfh"/ >
73- <div class="absolute inset-0 flex items-center justify-center" >
74- <div class="bg-white/90 p-4 rounded-xl shadow-lg flex items-center space-x-3 backdrop-blur-sm border border-primary/20" >
75- <span class="material-symbols-outlined text-primary text-3xl">map</span >
76- <span class="text-xs font-medium uppercase tracking-widest text-gray-600">Interactive Map Component</span >
77- </div >
78- </div >
70+ <div class="flex flex-col h-full" >
71+ <div class="flex justify-between items-end mb-2" >
72+ <label class="block text-sm font-semibold text -gray-700 uppercase tracking-wider" i18n="@@settingsLabelMap">Interactive Map</label >
73+ <button (click)="getCurrentLocation() " class="text-xs text-primary hover:text-primary-hover font-medium flex items-center transition-colors active:scale-95" >
74+ <span class="material-symbols-outlined text-[16px] mr-1">my_location</span >
75+ <span i18n="@@settingsBtnGetLocation">Get Current Location</span >
76+ </button >
77+ </div >
78+ <div class="h-[235px] w-full rounded-2xl bg-gray-100 border border-gray-200 overflow-hidden relative group" #mapContainer >
79+ <!-- Leaflet Map Container -- >
7980 </div>
8081 </div>
8182 </div>
@@ -90,6 +91,83 @@ export class BusinessProfileComponent {
9091 updateOwnerInfo = output < OwnerInfo > ( ) ;
9192 save = output < void > ( ) ;
9293
94+ mapContainer = viewChild < ElementRef < HTMLDivElement > > ( 'mapContainer' ) ;
95+ map : L . Map | undefined ;
96+ marker : L . Marker | undefined ;
97+
98+ constructor ( ) {
99+ effect ( ( ) => {
100+ const container = this . mapContainer ( ) ?. nativeElement ;
101+ if ( container && ! this . map ) {
102+ this . initMap ( container ) ;
103+ }
104+ } ) ;
105+
106+ effect ( ( ) => {
107+ const loc = this . location ( ) ;
108+ if ( this . map && this . marker && loc && loc . latitude && loc . longitude ) {
109+ this . map . setView ( [ loc . latitude , loc . longitude ] , this . map . getZoom ( ) || 15 ) ;
110+ this . marker . setLatLng ( [ loc . latitude , loc . longitude ] ) ;
111+ }
112+ } ) ;
113+ }
114+
115+ getCurrentLocation ( ) {
116+ if ( navigator . geolocation ) {
117+ navigator . geolocation . getCurrentPosition (
118+ ( position ) => {
119+ this . onLocationChange ( 'latitude' , position . coords . latitude ) ;
120+ this . onLocationChange ( 'longitude' , position . coords . longitude ) ;
121+ } ,
122+ ( error ) => {
123+ console . error ( "Error getting location: " , error ) ;
124+ alert ( "Could not get your location. Please check browser permissions." ) ;
125+ }
126+ ) ;
127+ } else {
128+ alert ( "Geolocation is not supported by this browser." ) ;
129+ }
130+ }
131+
132+ private initMap ( container : HTMLDivElement ) {
133+ const defaultLat = this . location ( ) ?. latitude || 38.53575 ;
134+ const defaultLng = this . location ( ) ?. longitude || 68.77905 ;
135+
136+ // Fix leaflet default icon paths
137+ const iconDefault = L . icon ( {
138+ iconRetinaUrl : 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png' ,
139+ iconUrl : 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png' ,
140+ shadowUrl : 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png' ,
141+ iconSize : [ 25 , 41 ] ,
142+ iconAnchor : [ 12 , 41 ] ,
143+ popupAnchor : [ 1 , - 34 ] ,
144+ tooltipAnchor : [ 16 , - 28 ] ,
145+ shadowSize : [ 41 , 41 ]
146+ } ) ;
147+ L . Marker . prototype . options . icon = iconDefault ;
148+
149+ this . map = L . map ( container ) . setView ( [ defaultLat , defaultLng ] , 15 ) ;
150+
151+ L . tileLayer ( 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png' , {
152+ maxZoom : 19 ,
153+ attribution : '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
154+ } ) . addTo ( this . map ) ;
155+
156+ this . marker = L . marker ( [ defaultLat , defaultLng ] , { draggable : true } ) . addTo ( this . map ) ;
157+
158+ this . marker . on ( 'dragend' , ( event ) => {
159+ const marker = event . target ;
160+ const position = marker . getLatLng ( ) ;
161+ this . onLocationChange ( 'latitude' , position . lat ) ;
162+ this . onLocationChange ( 'longitude' , position . lng ) ;
163+ } ) ;
164+
165+ this . map . on ( 'click' , ( event : L . LeafletMouseEvent ) => {
166+ this . onLocationChange ( 'latitude' , event . latlng . lat ) ;
167+ this . onLocationChange ( 'longitude' , event . latlng . lng ) ;
168+ } ) ;
169+ }
170+
93171 onLocationChange ( field : keyof AdminLocation , value : any ) {
94172 this . updateLocation . emit ( { ...this . location ( ) , [ field ] : value } ) ;
95173 }
0 commit comments