google maps added
This commit is contained in:
parent
8345e1fe69
commit
742646268c
91
package-lock.json
generated
91
package-lock.json
generated
@ -8,6 +8,7 @@
|
||||
"name": "frontend",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@react-google-maps/api": "^2.20.8",
|
||||
"@types/leaflet": "^1.9.21",
|
||||
"jspdf": "^4.2.1",
|
||||
"jspdf-autotable": "^5.0.8",
|
||||
@ -447,6 +448,22 @@
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
}
|
||||
},
|
||||
"node_modules/@googlemaps/js-api-loader": {
|
||||
"version": "1.16.8",
|
||||
"resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.16.8.tgz",
|
||||
"integrity": "sha512-CROqqwfKotdO6EBjZO/gQGVTbeDps5V7Mt9+8+5Q+jTg5CRMi3Ii/L9PmV3USROrt2uWxtGzJHORmByxyo9pSQ==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@googlemaps/markerclusterer": {
|
||||
"version": "2.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@googlemaps/markerclusterer/-/markerclusterer-2.5.3.tgz",
|
||||
"integrity": "sha512-x7lX0R5yYOoiNectr10wLgCBasNcXFHiADIBdmn7jQllF2B5ENQw5XtZK+hIw4xnV0Df0xhN4LN98XqA5jaiOw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"supercluster": "^8.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanfs/core": {
|
||||
"version": "0.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
|
||||
@ -592,6 +609,36 @@
|
||||
"url": "https://github.com/sponsors/Boshen"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-google-maps/api": {
|
||||
"version": "2.20.8",
|
||||
"resolved": "https://registry.npmjs.org/@react-google-maps/api/-/api-2.20.8.tgz",
|
||||
"integrity": "sha512-wtLYFtCGXK3qbIz1H5to3JxbosPnKsvjDKhqGylXUb859EskhzR7OpuNt0LqdLarXUtZCJTKzPn3BNaekNIahg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@googlemaps/js-api-loader": "1.16.8",
|
||||
"@googlemaps/markerclusterer": "2.5.3",
|
||||
"@react-google-maps/infobox": "2.20.0",
|
||||
"@react-google-maps/marker-clusterer": "2.20.0",
|
||||
"@types/google.maps": "3.58.1",
|
||||
"invariant": "2.2.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8 || ^17 || ^18 || ^19",
|
||||
"react-dom": "^16.8 || ^17 || ^18 || ^19"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-google-maps/infobox": {
|
||||
"version": "2.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-google-maps/infobox/-/infobox-2.20.0.tgz",
|
||||
"integrity": "sha512-03PJHjohhaVLkX6+NHhlr8CIlvUxWaXhryqDjyaZ8iIqqix/nV8GFdz9O3m5OsjtxtNho09F/15j14yV0nuyLQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@react-google-maps/marker-clusterer": {
|
||||
"version": "2.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-google-maps/marker-clusterer/-/marker-clusterer-2.20.0.tgz",
|
||||
"integrity": "sha512-tieX9Va5w1yP88vMgfH1pHTacDQ9TgDTjox3tLlisKDXRQWdjw+QeVVghhf5XqqIxXHgPdcGwBvKY6UP+SIvLw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@react-leaflet/core": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz",
|
||||
@ -1271,6 +1318,12 @@
|
||||
"integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/google.maps": {
|
||||
"version": "3.58.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.58.1.tgz",
|
||||
"integrity": "sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
@ -2267,7 +2320,6 @@
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-json-stable-stringify": {
|
||||
@ -2498,6 +2550,15 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/invariant": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/iobuffer": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz",
|
||||
@ -2548,7 +2609,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jsesc": {
|
||||
@ -2624,6 +2684,12 @@
|
||||
"jspdf": "^2 || ^3 || ^4"
|
||||
}
|
||||
},
|
||||
"node_modules/kdbush": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.1.0.tgz",
|
||||
"integrity": "sha512-e9vurzrXJQrFX6ckpHP3bvj5l+9CnYzkxDNnNQ1h2QTqdWsUAJgXiKdGNcOa1EY85dU8KbQ+z/FdQdB7P+9yfQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||
@ -2931,6 +2997,18 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||
@ -3461,6 +3539,15 @@
|
||||
"node": ">=0.1.14"
|
||||
}
|
||||
},
|
||||
"node_modules/supercluster": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz",
|
||||
"integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"kdbush": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/svg-pathdata": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-google-maps/api": "^2.20.8",
|
||||
"@types/leaflet": "^1.9.21",
|
||||
"jspdf": "^4.2.1",
|
||||
"jspdf-autotable": "^5.0.8",
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
// docs under src/docs/api.
|
||||
|
||||
export const APP_ID = '434';
|
||||
export const BASE_URL = 'https://sandbox.getzino.in';
|
||||
export const BASE_URL = 'https://dev.getzino.in';
|
||||
|
||||
// --- Order Booking (src/docs/api/order_booking.md) ---
|
||||
export const ORDER_BOOKING = {
|
||||
@ -212,3 +212,11 @@ export const ROUTE_WISE_DISTRIBUTORS: Record<string, string[]> = {
|
||||
export const SALES_REPORT_SO_NAMES = [
|
||||
'Surya C'
|
||||
];
|
||||
|
||||
// --- Pipeline Endpoints ---
|
||||
export const PIPELINE = {
|
||||
endpoints: {
|
||||
nearestStores: '/api/papi2/nearest-stores',
|
||||
dailySalesReport: '/api/papi2/daily-sales-report'
|
||||
}
|
||||
};
|
||||
|
||||
@ -380,6 +380,7 @@ export function DailyLogDetail({ instanceId, refreshKey, onPunchOut, onBack }: D
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
254
src/components/maps/DailyLogMap.tsx
Normal file
254
src/components/maps/DailyLogMap.tsx
Normal file
@ -0,0 +1,254 @@
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { useJsApiLoader, GoogleMap, Marker, InfoWindow } from '@react-google-maps/api';
|
||||
import { Loader2, MapPin } from 'lucide-react';
|
||||
import { PIPELINE } from '../../api/config';
|
||||
import { dailyReportsClient } from '../../api/clients';
|
||||
|
||||
interface StoreLocation {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
}
|
||||
|
||||
interface Store {
|
||||
area: string;
|
||||
business_name: string;
|
||||
distance_km: number;
|
||||
location: StoreLocation;
|
||||
route_name: string;
|
||||
store_code: string;
|
||||
}
|
||||
|
||||
interface NearestStoresResponse {
|
||||
message: string;
|
||||
response: {
|
||||
count: number;
|
||||
stores: Store[];
|
||||
success: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
const mapContainerStyle = {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
borderRadius: '0px'
|
||||
};
|
||||
|
||||
const defaultCenter = { lat: 12.9716, lng: 77.5946 };
|
||||
|
||||
export function DailyLogMap({
|
||||
latitude,
|
||||
longitude,
|
||||
showStoreList = false
|
||||
}: {
|
||||
latitude?: number | string | null;
|
||||
longitude?: number | string | null;
|
||||
showStoreList?: boolean;
|
||||
}) {
|
||||
const [userLocation, setUserLocation] = useState<{ lat: number, lng: number } | null>(null);
|
||||
const [stores, setStores] = useState<Store[]>([]);
|
||||
const [selectedStore, setSelectedStore] = useState<Store | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const mapRef = useRef<google.maps.Map | null>(null);
|
||||
|
||||
const isLocalhost = typeof window !== 'undefined' && (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1');
|
||||
|
||||
const { isLoaded } = useJsApiLoader({
|
||||
id: 'google-map-script',
|
||||
googleMapsApiKey: isLocalhost ? '' : (import.meta.env.VITE_GOOGLE_MAPS_API_KEY || '')
|
||||
});
|
||||
|
||||
const fetchNearestStores = async (lat: number, lng: number) => {
|
||||
try {
|
||||
const data = await dailyReportsClient.request<NearestStoresResponse>(
|
||||
'POST',
|
||||
PIPELINE.endpoints.nearestStores,
|
||||
{
|
||||
latitude: lat,
|
||||
longitude: lng
|
||||
},
|
||||
{
|
||||
'accept': 'application/json, text/plain, */*',
|
||||
'groupid': '25',
|
||||
'orgid': '57',
|
||||
'templateid': '189',
|
||||
'x-pipeline-version': 'draft'
|
||||
}
|
||||
);
|
||||
|
||||
if (data.response && data.response.stores) {
|
||||
setStores(data.response.stores);
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('An error occurred while fetching stores.', err);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// If coords provided in props, use them
|
||||
if (latitude && longitude && String(latitude).trim() !== '—' && String(longitude).trim() !== '—') {
|
||||
const lat = Number(latitude);
|
||||
const lng = Number(longitude);
|
||||
if (!isNaN(lat) && !isNaN(lng)) {
|
||||
setUserLocation({ lat, lng });
|
||||
fetchNearestStores(lat, lng);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise fallback to whatever tactic used for mobile
|
||||
if (!navigator.geolocation) {
|
||||
setError('Geolocation is not supported by your browser.');
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(position) => {
|
||||
const lat = position.coords.latitude;
|
||||
const lng = position.coords.longitude;
|
||||
setUserLocation({ lat, lng });
|
||||
fetchNearestStores(lat, lng);
|
||||
},
|
||||
(err) => {
|
||||
setError(err.message || 'Failed to get location');
|
||||
},
|
||||
{ enableHighAccuracy: true }
|
||||
);
|
||||
}, [latitude, longitude]);
|
||||
|
||||
const onLoad = useCallback(function callback(map: google.maps.Map) {
|
||||
mapRef.current = map;
|
||||
if (userLocation) {
|
||||
const bounds = new window.google.maps.LatLngBounds();
|
||||
bounds.extend(userLocation);
|
||||
map.fitBounds(bounds);
|
||||
|
||||
const listener = window.google.maps.event.addListener(map, 'idle', () => {
|
||||
if (map.getZoom()! > 15) {
|
||||
map.setZoom(15);
|
||||
}
|
||||
window.google.maps.event.removeListener(listener);
|
||||
});
|
||||
}
|
||||
}, [userLocation]);
|
||||
|
||||
useEffect(() => {
|
||||
if (mapRef.current && userLocation && stores.length > 0) {
|
||||
const bounds = new window.google.maps.LatLngBounds();
|
||||
bounds.extend(userLocation);
|
||||
stores.forEach(store => {
|
||||
if (store.location) {
|
||||
const lat = Number(store.location.latitude);
|
||||
const lng = Number(store.location.longitude);
|
||||
if (!isNaN(lat) && !isNaN(lng)) {
|
||||
bounds.extend({ lat, lng });
|
||||
}
|
||||
}
|
||||
});
|
||||
mapRef.current.fitBounds(bounds);
|
||||
}
|
||||
}, [stores, userLocation]);
|
||||
|
||||
if (!isLoaded) {
|
||||
return (
|
||||
<div className="w-full h-[320px] flex items-center justify-center bg-slate-50 rounded-xl border border-slate-200">
|
||||
<Loader2 className="w-8 h-8 text-slate-400 animate-spin" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full h-full flex flex-col bg-transparent min-h-[320px]">
|
||||
{error && (
|
||||
<div className="bg-red-50 text-red-600 p-3 mb-4 rounded-lg text-sm border border-red-100">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="w-full min-h-[320px] flex-1 relative rounded-none border border-slate-200 rounded-xl overflow-hidden">
|
||||
<GoogleMap
|
||||
mapContainerStyle={mapContainerStyle}
|
||||
center={userLocation || defaultCenter}
|
||||
zoom={userLocation ? 13 : 5}
|
||||
onLoad={onLoad}
|
||||
options={{
|
||||
streetViewControl: false,
|
||||
mapTypeControl: false,
|
||||
fullscreenControl: false
|
||||
}}
|
||||
>
|
||||
{/* User's Current Location Marker */}
|
||||
{userLocation && (
|
||||
<Marker
|
||||
position={userLocation}
|
||||
icon={{
|
||||
url: 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png'
|
||||
}}
|
||||
title="Location"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Stores Markers */}
|
||||
{stores.map((store) => {
|
||||
if (!store.location) return null;
|
||||
const lat = Number(store.location.latitude);
|
||||
const lng = Number(store.location.longitude);
|
||||
if (isNaN(lat) || isNaN(lng)) return null;
|
||||
|
||||
return (
|
||||
<Marker
|
||||
key={store.store_code}
|
||||
position={{ lat, lng }}
|
||||
onClick={() => setSelectedStore(store)}
|
||||
title={store.business_name}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* Info Window for Selected Store */}
|
||||
{selectedStore && selectedStore.location && !isNaN(Number(selectedStore.location.latitude)) && (
|
||||
<InfoWindow
|
||||
position={{ lat: Number(selectedStore.location.latitude), lng: Number(selectedStore.location.longitude) }}
|
||||
onCloseClick={() => setSelectedStore(null)}
|
||||
>
|
||||
<div className="p-1 max-w-[200px]">
|
||||
<h3 className="font-semibold text-sm text-slate-800">{selectedStore.business_name}</h3>
|
||||
<p className="text-xs text-slate-500 mt-1">{selectedStore.area}</p>
|
||||
<div className="flex justify-between items-center mt-2 pt-2 border-t border-slate-100">
|
||||
<span className="text-[10px] bg-blue-50 text-blue-600 px-1.5 py-0.5 rounded border border-blue-100">
|
||||
{selectedStore.route_name}
|
||||
</span>
|
||||
<span className="text-[10px] text-slate-400 font-medium">
|
||||
{selectedStore.distance_km} km
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</InfoWindow>
|
||||
)}
|
||||
</GoogleMap>
|
||||
</div>
|
||||
|
||||
{showStoreList && (
|
||||
<div className="mt-4 p-5 flex flex-col gap-4 bg-[var(--tiles-card-bg)] rounded-xl border border-slate-200">
|
||||
<h3 className="font-bold text-slate-800 text-sm m-0 flex items-center gap-2 uppercase tracking-wider">
|
||||
<MapPin size={16} className="text-slate-500" /> Nearby Stores
|
||||
</h3>
|
||||
<div className="flex flex-col gap-3">
|
||||
{stores.length > 0 ? (
|
||||
stores.map((store) => (
|
||||
<div key={store.store_code} className="flex flex-col p-3 rounded-lg border border-slate-100 bg-slate-50 hover:bg-slate-100 transition-colors cursor-pointer" onClick={() => setSelectedStore(store)}>
|
||||
<span className="font-bold text-slate-800 text-sm">{store.business_name}</span>
|
||||
<span className="text-xs text-slate-500">{store.store_code}</span>
|
||||
{store.distance_km != null && (
|
||||
<span className="text-xs text-[#1b37a5] font-semibold mt-1">{store.distance_km.toFixed(2)} km away</span>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<span className="text-sm text-slate-400 italic">No nearby stores found.</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -2,6 +2,7 @@ import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { Modal } from '../components/reusable';
|
||||
import { DailyLogsView } from '../components/rv';
|
||||
import { DailyLogDetail } from '../components/dv';
|
||||
import { DailyLogMap } from '../components/maps/DailyLogMap';
|
||||
import { useState } from 'react';
|
||||
import { Button } from '../components/buttons/Button';
|
||||
import { Plus, MapPin } from 'lucide-react';
|
||||
@ -20,21 +21,13 @@ export function DailyLogsPage() {
|
||||
const [refreshKey, setRefreshKey] = useState(0);
|
||||
|
||||
const mapComponent = (
|
||||
<div className="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden flex flex-col h-full min-h-[320px]">
|
||||
<div className="p-4 border-b border-slate-100 flex items-center gap-2">
|
||||
<div className="!bg-[var(--tiles-card-bg)] rounded-lg shadow-sm border border-gray-100 overflow-hidden flex flex-col h-full min-h-[320px]">
|
||||
<div className="px-5 py-4 border-b border-[var(--z-block-border)] flex items-center gap-2">
|
||||
<MapPin size={18} className="text-slate-400" />
|
||||
<h3 className="text-slate-800 font-bold">Activity Locations</h3>
|
||||
<h3 className="text-md font-semibold text-[var(--z-text-default)]">Activity Locations</h3>
|
||||
</div>
|
||||
<div className="flex-1 relative bg-slate-50">
|
||||
<iframe
|
||||
title="Logs Map"
|
||||
width="100%"
|
||||
height="100%"
|
||||
style={{ border: 0, position: 'absolute', inset: 0 }}
|
||||
loading="lazy"
|
||||
allowFullScreen
|
||||
src="https://maps.google.com/maps?q=activity&hl=en&z=10&output=embed"
|
||||
></iframe>
|
||||
<DailyLogMap />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -2,6 +2,7 @@ import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { Modal } from '../components/reusable';
|
||||
import { DailyLogsView } from '../components/rv';
|
||||
import { DailyLogDetail } from '../components/dv';
|
||||
import { DailyLogMap } from '../components/maps/DailyLogMap';
|
||||
import { useState } from 'react';
|
||||
import { Button } from '../components/buttons/Button';
|
||||
import { Plus, MapPin } from 'lucide-react';
|
||||
@ -23,21 +24,13 @@ export function MyDailyLogsPage() {
|
||||
const { userEmail } = useAuth();
|
||||
|
||||
const mapComponent = (
|
||||
<div className="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden flex flex-col h-full min-h-[320px]">
|
||||
<div className="p-4 border-b border-slate-100 flex items-center gap-2">
|
||||
<div className="!bg-[var(--tiles-card-bg)] rounded-lg shadow-sm border border-gray-100 overflow-hidden flex flex-col h-full min-h-[320px]">
|
||||
<div className="px-5 py-4 border-b border-[var(--z-block-border)] flex items-center gap-2">
|
||||
<MapPin size={18} className="text-slate-400" />
|
||||
<h3 className="text-slate-800 font-bold">Activity Locations</h3>
|
||||
<h3 className="text-md font-semibold text-[var(--z-text-default)]">Activity Locations</h3>
|
||||
</div>
|
||||
<div className="flex-1 relative bg-slate-50">
|
||||
<iframe
|
||||
title="Logs Map"
|
||||
width="100%"
|
||||
height="100%"
|
||||
style={{ border: 0, position: 'absolute', inset: 0 }}
|
||||
loading="lazy"
|
||||
allowFullScreen
|
||||
src="https://maps.google.com/maps?q=activity&hl=en&z=10&output=embed"
|
||||
></iframe>
|
||||
<DailyLogMap />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -2,6 +2,7 @@ import { useState } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { StoresView } from '../components/rv';
|
||||
import { StoreDetail } from '../components/dv';
|
||||
import { DailyLogMap } from '../components/maps/DailyLogMap';
|
||||
import { Button } from '../components/buttons/Button';
|
||||
import { Plus, MapPin } from 'lucide-react';
|
||||
import { DynamicForm } from '../components/forms/DynamicForm';
|
||||
@ -56,21 +57,13 @@ export function StoresPage() {
|
||||
}
|
||||
|
||||
const mapComponent = (
|
||||
<div className="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden flex flex-col h-full min-h-[320px]">
|
||||
<div className="p-4 border-b border-slate-100 flex items-center gap-2">
|
||||
<div className="!bg-[var(--tiles-card-bg)] rounded-lg shadow-sm border border-gray-100 overflow-hidden flex flex-col h-full min-h-[320px]">
|
||||
<div className="px-5 py-4 border-b border-[var(--z-block-border)] flex items-center gap-2">
|
||||
<MapPin size={18} className="text-slate-400" />
|
||||
<h3 className="text-slate-800 font-bold">Location Spread</h3>
|
||||
<h3 className="text-md font-semibold text-[var(--z-text-default)]">Location Spread</h3>
|
||||
</div>
|
||||
<div className="flex-1 relative bg-slate-50">
|
||||
<iframe
|
||||
title="Stores Map"
|
||||
width="100%"
|
||||
height="100%"
|
||||
style={{ border: 0, position: 'absolute', inset: 0 }}
|
||||
loading="lazy"
|
||||
allowFullScreen
|
||||
src="https://maps.google.com/maps?q=stores&hl=en&z=10&output=embed"
|
||||
></iframe>
|
||||
<DailyLogMap />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user