- {/* Fallback Input */}
- {(!data.tripData.googleMapsKey && isEnvKeyMissing) && (
+ {/* Manual Input if Env key is missing */}
+ {isKeyMissing && !data.tripData.googleMapsKey && (
-
Nie wykryto klucza w .env
+
Brak klucza w konfiguracji (VITE_GOOGLE_MAPS_KEY)
- System automatycznie wklei klucz zapasowy. Jeśli to nie nastąpiło, wklej go poniżej.
+ Wklej klucz ręcznie poniżej, aby mapy zadziałały.
= ({ data, updateData, onGenerate,
- {/* BIG TRAVEL MODE SELECTOR */}
- {/* Validation Message if missing */}
{!data.tripData.travelMode && (
* Wybór rodzaju trasy jest wymagany
@@ -378,8 +352,6 @@ const StepDetails: React.FC = ({ data, updateData, onGenerate,
)}
-
- {/* START POINT */}
@@ -404,11 +376,9 @@ const StepDetails: React.FC = ({ data, updateData, onGenerate,
placeholder="Opis startu (np. Zbiórka o 6:00)"
/>
- {/* Placeholder for alignment */}
- {/* STOPS */}
{data.tripData.stops.map((stop, index) => (
@@ -454,7 +424,6 @@ const StepDetails: React.FC = ({ data, updateData, onGenerate,
- {/* END POINT */}
@@ -479,15 +448,13 @@ const StepDetails: React.FC = ({ data, updateData, onGenerate,
placeholder="Opis końca (np. Nareszcie piwo)"
/>
- {/* Placeholder for alignment */}
-
)}
- {/* STANDARDOWE POLA */}
+ {/* Standard Fields */}
@@ -511,7 +478,6 @@ const StepDetails: React.FC = ({ data, updateData, onGenerate,
/>
- {/* File Upload */}
= ({ data, updateData, onGenerate,
{error &&
{error}
}
- {/* File List */}
{data.files.length > 0 && (
{data.files.map((file) => (
diff --git a/components/TripMap.tsx b/components/TripMap.tsx
index 2328a08..ea85f59 100644
--- a/components/TripMap.tsx
+++ b/components/TripMap.tsx
@@ -18,29 +18,17 @@ const TripMap: React.FC
= ({ tripData }) => {
const [routingError, setRoutingError] = useState(null);
const [retryCount, setRetryCount] = useState(0);
- // --- HARDCODED FALLBACK KEY ---
- const AUTO_PASTE_KEY = 'AIzaSyAq9IgZswt5j7GGfH2s-ESenHmfvWFCFCg';
-
- // Directly access the environment variable OR fallback to manual input OR auto-paste
+ // STRICT MODE: Use VITE_GOOGLE_MAPS_KEY
const getEffectiveKey = () => {
- // 1. Check manual override
+ // 1. Check manual override from user input
if (tripData.googleMapsKey) return tripData.googleMapsKey;
-
// 2. Check Vite env
- const viteKey = getEnvVar('VITE_GOOGLE_MAPS_KEY');
- if (viteKey) return viteKey;
-
- // 3. Check Standard process.env
- const procKey = getEnvVar('GOOGLE_MAPS_KEY');
- if (procKey) return procKey;
-
- // 4. Fallback
- return AUTO_PASTE_KEY;
+ return getEnvVar('VITE_GOOGLE_MAPS_KEY');
};
const apiKey = getEffectiveKey();
- // Load script if not present (e.g. refreshed on Result page)
+ // Load script if not present
useEffect(() => {
if ((window as any).google?.maps) {
setScriptLoaded(true);
@@ -49,7 +37,6 @@ const TripMap: React.FC = ({ tripData }) => {
if (!apiKey) return;
- // Check if script exists in DOM
if (document.querySelector(`script[src*="maps.googleapis.com/maps/api/js"]`)) {
const check = setInterval(() => {
if ((window as any).google?.maps) {
@@ -68,7 +55,7 @@ const TripMap: React.FC = ({ tripData }) => {
}, [apiKey]);
- // Calculate Route using Directions Service
+ // Calculate Route
useEffect(() => {
if (!scriptLoaded || !tripData.startPoint.place || !tripData.endPoint.place) return;
if (!(window as any).google) return;
@@ -79,23 +66,13 @@ const TripMap: React.FC = ({ tripData }) => {
try {
const directionsService = new (window as any).google.maps.DirectionsService();
-
- // Prepare valid waypoints (exclude empty stops)
const waypoints = tripData.stops
.filter(s => s.place && s.place.trim().length > 2)
.map(s => ({ location: s.place, stopover: true }));
- // Determine Travel Mode
const gMaps = (window as any).google.maps;
const mode = tripData.travelMode === 'WALKING' ? gMaps.TravelMode.WALKING : gMaps.TravelMode.DRIVING;
- console.log("TripMap: Requesting route...", {
- origin: tripData.startPoint.place,
- dest: tripData.endPoint.place,
- mode: tripData.travelMode,
- waypointsCount: waypoints.length
- });
-
const result = await new Promise((resolve, reject) => {
directionsService.route({
origin: tripData.startPoint.place,
@@ -106,31 +83,23 @@ const TripMap: React.FC = ({ tripData }) => {
if (status === 'OK') {
resolve(response);
} else {
- console.warn("TripMap: Directions API Error", status);
reject(status);
}
});
});
- // Extract overview polyline
- const polyline = result.routes[0].overview_polyline;
-
- setEncodedPolyline(polyline);
+ setEncodedPolyline(result.routes[0].overview_polyline);
setImgError(false);
} catch (error: any) {
console.error("Directions Service Failed:", error);
-
- // Specific Error Handling
if (error === 'REQUEST_DENIED') {
- setRoutingError("API 'Directions API' nie jest włączone w Google Cloud. Mapa pokazuje linię prostą.");
+ setRoutingError("API 'Directions API' nie jest włączone.");
} else if (error === 'ZERO_RESULTS') {
- const modeName = tripData.travelMode === 'WALKING' ? 'pieszej' : 'samochodowej';
- setRoutingError(`Nie znaleziono drogi ${modeName} pomiędzy tymi punktami.`);
+ setRoutingError(`Nie znaleziono drogi pomiędzy punktami.`);
} else {
setRoutingError(`Błąd wyznaczania trasy: ${error}`);
}
-
- setEncodedPolyline(null); // Fallback to straight lines
+ setEncodedPolyline(null);
} finally {
setIsRouting(false);
}
@@ -140,13 +109,12 @@ const TripMap: React.FC = ({ tripData }) => {
}, [scriptLoaded, tripData.startPoint.place, tripData.endPoint.place, tripData.stops, tripData.travelMode, retryCount]);
- // Construct Google Static Maps URL
const getMapUrl = () => {
if (!apiKey) return null;
const baseUrl = 'https://maps.googleapis.com/maps/api/staticmap';
const size = '600x400';
- const scale = '2'; // Retina
+ const scale = '2';
const format = 'png';
const maptype = 'roadmap';
@@ -155,11 +123,9 @@ const TripMap: React.FC = ({ tripData }) => {
if (!startPlace || !endPlace) return null;
- // Markers
const startMarker = `markers=color:green|label:S|${encodeURIComponent(startPlace)}`;
const endMarker = `markers=color:red|label:F|${encodeURIComponent(endPlace)}`;
- // Stop Markers
const stopMarkers = tripData.stops
.filter(s => s.place.trim() !== '')
.map((s, i) => `markers=color:blue|label:${i+1}|${encodeURIComponent(s.place)}`)
@@ -175,15 +141,11 @@ const TripMap: React.FC = ({ tripData }) => {
...tripData.stops.filter(s => s.place.trim() !== '').map(s => s.place),
endPlace
].map(p => encodeURIComponent(p)).join('|');
-
path = `path=color:0xEA4420ff|weight:5|${pathPoints}`;
}
let url = `${baseUrl}?size=${size}&scale=${scale}&format=${format}&maptype=${maptype}&${startMarker}&${endMarker}&${path}&key=${apiKey}`;
-
- if (stopMarkers) {
- url += `&${stopMarkers}`;
- }
+ if (stopMarkers) url += `&${stopMarkers}`;
return url;
};
@@ -192,32 +154,28 @@ const TripMap: React.FC = ({ tripData }) => {
const handleDownload = async () => {
if (!mapContainerRef.current) return;
-
try {
const canvas = await html2canvas(mapContainerRef.current, {
useCORS: true,
allowTaint: true,
backgroundColor: '#ffffff'
});
-
const link = document.createElement('a');
link.download = 'trasa-wycieczki.png';
link.href = canvas.toDataURL('image/png');
link.click();
} catch (e) {
- console.error("Download failed", e);
alert("Nie udało się pobrać mapy.");
}
};
- // ERROR STATE 1: MISSING KEY
if (!apiKey) {
return (
Brak Klucza API
- Wprowadź klucz w kroku "Szczegóły" lub dodaj go do pliku .env.
+ Skonfiguruj zmienną VITE_GOOGLE_MAPS_KEY w panelu.
);
@@ -250,18 +208,12 @@ const TripMap: React.FC = ({ tripData }) => {
- {/* Warning Banner for Directions API issues */}
{routingError && (
-
Widzisz prostą linię zamiast drogi?
+
Info Trasy:
{routingError}
-
- {routingError.includes("Directions API")
- ? <>Rozwiązanie: Wejdź w Google Cloud Console → APIs & Services → Włącz "Directions API".>
- : <>Jeśli idziesz szlakiem, upewnij się, że wybrałeś tryb "Pieszo".>}
-
)}
@@ -270,7 +222,6 @@ const TripMap: React.FC
= ({ tripData }) => {
ref={mapContainerRef}
className="bg-white p-2 border border-gray-200 rounded-xl shadow-sm overflow-hidden relative group min-h-[250px] flex items-center justify-center"
>
- {/* Map Image */}
{mapUrl && !imgError && !isRouting ? (
= ({ tripData }) => {
{isRouting ? (
<>
- Rysowanie dokładnej trasy ({tripData.travelMode})...
+ Rysowanie trasy...
>
) : imgError ? (
-
Błąd ładowania obrazka mapy (Static Maps API)
-
-
Możliwe przyczyny błędu "g.co/staticmaperror":
-
- - Maps Static API nie jest włączone w konsoli Google Cloud (To inne API niż Places/JavaScript!).
- - Brak podpiętej karty płatniczej w projekcie Google Cloud.
- - Klucz API: {apiKey.slice(0,6)}... jest niepoprawny lub ma restrykcje HTTP, które blokują serwer zdjęć.
-
-
+
Błąd ładowania mapy
) : (
{tripData.startPoint.place ? 'Czekam na dane...' : 'Uzupełnij punkty trasy...'}
@@ -307,22 +250,12 @@ const TripMap: React.FC = ({ tripData }) => {
)}
- {/* Branding Overlay */}
{!imgError && mapUrl && !isRouting && (
Generated by PromptStory
)}
-
- {/* Helper Text below map */}
-
-
- {encodedPolyline && encodedPolyline.length < 8000
- ? `*Trasa wyznaczona automatycznie (${tripData.travelMode === 'WALKING' ? 'szlaki/chodniki' : 'drogi'}).`
- : "*Trasa uproszczona (linia prosta) - włącz Directions API lub zmień tryb."}
-
-
);
};
diff --git a/utils/envUtils.ts b/utils/envUtils.ts
index 2d4a088..1801d81 100644
--- a/utils/envUtils.ts
+++ b/utils/envUtils.ts
@@ -1,27 +1,28 @@
/**
- * Safely retrieves environment variables in both Vite (browser) and Node environments.
- * Prevents "ReferenceError: process is not defined" crashes in production builds.
+ * Safely retrieves environment variables in Vite environment.
+ * In Vite, variables must start with VITE_ to be exposed to the client.
*/
export const getEnvVar = (key: string): string => {
// 1. Try Vite / Modern Browser approach (import.meta.env)
try {
// @ts-ignore
- if (typeof import.meta !== 'undefined' && import.meta.env && import.meta.env[key]) {
+ if (typeof import.meta !== 'undefined' && import.meta.env) {
// @ts-ignore
- return import.meta.env[key];
+ const val = import.meta.env[key];
+ if (val) return val;
}
} catch (e) {
- // Ignore errors if import.meta is not supported
+ // Ignore errors
}
- // 2. Try Node / Webpack / Polyfilled approach (process.env)
+ // 2. Legacy/Fallback for some test environments
try {
- if (typeof process !== 'undefined' && process.env && process.env[key]) {
+ if (typeof process !== 'undefined' && process.env) {
return process.env[key] || '';
}
} catch (e) {
- // Ignore errors if process is not defined
+ // Ignore
}
return '';