Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions components/GenerateMap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const selectedLongitude = ref(props.mapLongitude);
const selectedStyle = ref(props.availableMapStyles[0].url);
const selectedZoom = ref(props.mapZoom);
const showModal = ref(false);
const customMapboxStyleRendered = ref(false);
const mapLoadError = ref(false);

const emit = defineEmits(["updateMapParams", "handleMapRequest"]);

Expand Down Expand Up @@ -63,6 +65,14 @@ const updateMapParams = (updateObj: UpdateMapParams) => {
selectedStyle.value = value as string;
osmEnabled.value = false;
emit("updateMapParams", { param: "OsmEnabled", value: false });
// Reset custom mapbox style rendered state if switching to non-custom style
if (
typeof value === "string" &&
(!value.includes("mapbox://styles/") ||
value.includes("mapbox://styles/mapbox/"))
) {
customMapboxStyleRendered.value = false;
}
break;
case "Zoom":
selectedZoom.value = value as number;
Expand All @@ -71,6 +81,26 @@ const updateMapParams = (updateObj: UpdateMapParams) => {
}
};

/** Passes map style loaded event and any errors to the map sidebar. */
const handleMapStyleLoaded = (data: {
style: string;
success: boolean;
error?: string;
}) => {
if (
data.style.includes("mapbox://styles/") &&
!data.style.includes("mapbox://styles/mapbox/")
) {
if (data.success) {
customMapboxStyleRendered.value = true;
mapLoadError.value = false;
} else {
customMapboxStyleRendered.value = false;
mapLoadError.value = true;
}
}
};

/** Handles form submission and navigates to the home page. */
const handleFormSubmit = (formData: FormData) => {
emit("handleMapRequest", formData);
Expand All @@ -79,6 +109,24 @@ const handleFormSubmit = (formData: FormData) => {
router.push("/");
}, 3000);
};

const resetMapLoadError = () => {
mapLoadError.value = false;
};

const resetMapRendered = () => {
customMapboxStyleRendered.value = false;
};

watch(
() => localMapboxAccessToken.value,
(newVal) => {
// Reset error state when access token changes
if (newVal !== props.mapboxAccessToken) {
mapLoadError.value = false;
}
},
);
</script>

<template>
Expand All @@ -89,8 +137,12 @@ const handleFormSubmit = (formData: FormData) => {
:map-style="selectedStyle"
:mapbox-access-token="localMapboxAccessToken"
:osm-enabled="osmEnabled"
:custom-mapbox-style-rendered="customMapboxStyleRendered"
:map-load-error="mapLoadError"
@form-submitted="handleFormSubmit"
@update-map-params="updateMapParams"
@reset-map-load-error="resetMapLoadError"
@reset-map-rendered="resetMapRendered"
/>
<MapNavigation
:map-latitude="selectedLatitude"
Expand All @@ -106,6 +158,7 @@ const handleFormSubmit = (formData: FormData) => {
:map-zoom="selectedZoom"
:osm-enabled="osmEnabled"
@update-map-params="updateMapParams"
@map-style-loaded="handleMapStyleLoaded"
/>
<div v-if="showModal" class="overlay"></div>
<div v-if="showModal" class="modal">
Expand Down
22 changes: 21 additions & 1 deletion components/GenerateMap/MapCanvas.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const selectedLatitude = ref(props.mapLatitude);
const selectedLongitude = ref(props.mapLongitude);
const selectedZoom = ref(props.mapZoom);

const emit = defineEmits(["updateMapParams"]);
const emit = defineEmits(["updateMapParams", "mapStyleLoaded"]);

onMounted(() => {
if (!props.mapboxAccessToken) {
Expand Down Expand Up @@ -231,6 +231,17 @@ const setMapStyle = (newVal: string) => {
if (map.value && props.mapboxAccessToken) {
mapboxgl.accessToken = props.mapboxAccessToken;
map.value.setStyle(newVal);

// Listen for the style to load and emit the event
map.value.once("styledata", () => {
emit("mapStyleLoaded", { style: newVal, success: true });
});

// Listen for style loading errors
map.value.once("error", (e) => {
console.error("Map style loading error:", e);
emit("mapStyleLoaded", { style: newVal, success: false, error: e.error });
});
}
};

Expand All @@ -256,6 +267,15 @@ watch(
if (newVal) setMapStyle(newVal);
},
);
watch(
() => props.mapboxAccessToken,
(newVal?: string) => {
if (newVal && map.value && props.mapStyle) {
// Reload the current style with the new token
setMapStyle(props.mapStyle);
}
},
);
watch(
() => props.mapZoom,
(newVal) => {
Expand Down
72 changes: 69 additions & 3 deletions components/GenerateMap/MapSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const props = defineProps<{
mapboxAccessToken: string;
mapBounds: string;
mapStyle: string;
customMapboxStyleRendered: boolean;
mapLoadError: boolean;
}>();

const { t } = useI18n();
Expand All @@ -30,6 +32,7 @@ const customMapboxStyleUrl = ref("");
const localMapboxAccessToken = ref(props.mapboxAccessToken);
const localMapStyle = ref(props.mapStyle);
const mapStyles = ref<MapStyleWithValue[]>([]);
const hasClickedRender = ref(false);
const form = reactive<FormData>({
title: "",
description: null,
Expand Down Expand Up @@ -60,6 +63,13 @@ const fetchMapStyles = () => {
/** Renders a custom Mapbox style if the URL is valid. */
const renderCustomStyle = () => {
if (/^mapbox:\/\/styles\/[^/]+\/[^/]+$/.test(customMapboxStyleUrl.value)) {
// Reset ALL validation states on each render attempt
hasClickedRender.value = true;

// Reset error state and rendered state to force fresh validation
emit("resetMapLoadError");
emit("resetMapRendered");

form.selectedStyle = customMapboxStyleUrl.value;
form.selectedStyleKey = "mapbox-custom";
emit("updateMapParams", {
Expand Down Expand Up @@ -115,7 +125,25 @@ const isValidMapboxStyleAndToken = computed(() => {
return isValidStyle && isValidToken;
});

const emit = defineEmits(["updateMapParams", "formSubmitted"]);
/** Computes whether the form can be submitted for mapbox-custom style. */
const canSubmitMapboxCustom = computed(() => {
if (selectedStyleKey.value !== "mapbox-custom") {
return true;
}
return hasClickedRender.value && props.customMapboxStyleRendered;
});

/** Computes whether the submit button should be disabled. */
const isSubmitDisabled = computed(() => {
return estimatedTiles.value > 275000 || !canSubmitMapboxCustom.value;
});

const emit = defineEmits([
"updateMapParams",
"formSubmitted",
"resetMapLoadError",
"resetMapRendered",
]);

/** Toggles the OpenStreetMap layer. */
const toggleOSM = () => {
Expand Down Expand Up @@ -203,6 +231,16 @@ watch(
}
},
);

watch(
() => selectedStyleKey.value,
(newVal) => {
// Reset validation state when switching away from mapbox-custom
if (newVal !== "mapbox-custom") {
hasClickedRender.value = false;
}
},
);
</script>

<template>
Expand Down Expand Up @@ -276,6 +314,34 @@ watch(
>
{{ t("render") }}
</button>

<div v-if="selectedStyleKey === 'mapbox-custom'" class="mt-2">
<div v-if="!hasClickedRender" class="text-yellow-600 text-sm">
{{ t("clickRenderToValidate") }}
</div>
<div
v-else-if="
hasClickedRender &&
!props.customMapboxStyleRendered &&
!props.mapLoadError
"
class="text-blue-600 text-sm"
>
{{ t("renderingMap") }}
</div>
<div
v-else-if="hasClickedRender && props.mapLoadError"
class="text-red-600 text-sm"
>
{{ t("mapLoadError") }}
</div>
<div
v-else-if="hasClickedRender && props.customMapboxStyleRendered"
class="text-green-600 text-sm"
>
{{ t("mapRenderedSuccessfully") }}
</div>
</div>
</div>

<div
Expand Down Expand Up @@ -401,9 +467,9 @@ watch(

<button
type="submit"
:disabled="estimatedTiles > 275000"
:disabled="isSubmitDisabled"
class="submit-button"
:class="{ 'submit-button-disabled': estimatedTiles > 275000 }"
:class="{ 'submit-button-disabled': isSubmitDisabled }"
>
{{ t("submitRequest") }}
</button>
Expand Down
14 changes: 9 additions & 5 deletions i18n/locales/en.json
Original file line number Diff line number Diff line change
@@ -1,33 +1,36 @@
{
"authMessage": "Please sign up or log in to access this application",
"auth0LoginError": "Error logging in with Auth0",
"authMessage": "Please sign up or log in to access this application",
"availableOfflineMaps": "Available Offline Maps",
"buttonThenDraw": "button on the top right of the screen, and draw an area on the map",
"centerLat": "Center lat",
"centerLong": "Center long",
"clickOrPressThe": "Click or press the",
"clickRenderToValidate": "Click 'Render' to validate your custom style",
"copied": "Copied",
"copyLink": "Copy Link",
"errorMessage": "Error Message",
"estimatedNumberOfTiles": "Estimated number of tiles",
"description": "Description",
"download": "Download",
"errorMessage": "Error Message",
"estimatedNumberOfTiles": "Estimated number of tiles",
"failed": "Failed",
"fileSize": "File Size",
"finishedOn": "Finished on",
"format": "Format",
"generateMap": "Generate Map",
"generateOfflineMap": "Generate Offline Map",
"includeOSMData": "Include OSM Data (labels not shown)",
"loginButton": "Sign up or log in",
"login": "Log in",
"loginButton": "Sign up or log in",
"loginError": "An error occurred while trying to log in",
"mapControls": "Map Controls",
"mapDeleteConfirmation": "Are you sure you want to delete this offline map? This action cannot be undone",
"mapDeleted": "Offline map request successfully resubmitted",
"mapWithFilesDeleted": "Offline map request (and associated files) deleted",
"mapLoadError": "Failed to load map style. Please check your URL and access token.",
"mapRenderedSuccessfully": "Map rendered successfully! You can now submit your request.",
"mapRequestResubmitted": "Offline map request successfully resubmitted",
"mapStyle": "Map Style",
"mapWithFilesDeleted": "Offline map request (and associated files) deleted",
"maximumZoomLevel": "Maximum Zoom Level",
"metadata": "Metadata",
"noCoordinatesProvided": "No coordinates provided",
Expand All @@ -45,6 +48,7 @@
"pleaseGenerateANewMap": "Please generate a new map",
"processing": "Processing",
"render": "Render",
"renderingMap": "Rendering map...",
"requestedOn": "Requested on",
"resubmit": "Resubmit",
"status": "Status",
Expand Down
14 changes: 9 additions & 5 deletions i18n/locales/es.json
Original file line number Diff line number Diff line change
@@ -1,33 +1,36 @@
{
"authMessage": "Por favor, regístrese o inicie sesión para acceder a esta aplicación",
"auth0LoginError": "Error al iniciar sesión con Auth0",
"authMessage": "Por favor, regístrese o inicie sesión para acceder a esta aplicación",
"availableOfflineMaps": "Mapas offline disponibles",
"buttonThenDraw": "botón en la esquina superior derecha de la pantalla y dibuja un área en el mapa",
"centerLat": "Centro lat",
"centerLong": "Centro long",
"clickOrPressThe": "Haz clic o presiona el",
"clickRenderToValidate": "Haz clic en 'Renderizar' para validar tu estilo personalizado",
"copied": "Copiado",
"copyLink": "Copiar enlace",
"errorMessage": "Mensaje de error",
"estimatedNumberOfTiles": "Número estimado de tiles",
"description": "Descripción",
"download": "Descargar",
"errorMessage": "Mensaje de error",
"estimatedNumberOfTiles": "Número estimado de tiles",
"failed": "Fallido",
"fileSize": "Tamaño del archivo",
"finishedOn": "Terminado en",
"format": "Formato",
"generateMap": "Generar mapa",
"generateOfflineMap": "Generar mapa offline",
"includeOSMData": "Incluir datos OSM (etiquetas no mostradas)",
"loginButton": "Regístrate o inicia sesión",
"login": "Iniciar sesión",
"loginButton": "Regístrate o inicia sesión",
"loginError": "Ocurrió un error al intentar iniciar sesión",
"mapControls": "Controles del mapa",
"mapDeleteConfirmation": "¿Estás seguro de que quieres eliminar este mapa offline? Esta acción no puede deshacerse",
"mapDeleted": "Solicitud de mapa offline reenviada con éxito",
"mapLoadError": "Error al cargar el estilo del mapa. Por favor, verifica tu URL y token de acceso.",
"mapRenderedSuccessfully": "¡Mapa renderizado con éxito! Ya puedes enviar tu solicitud.",
"mapRequestResubmitted": "Solicitud de mapa offline reenviada con éxito",
"mapWithFilesDeleted": "Solicitud de mapa offline (y archivos asociados) eliminada",
"mapStyle": "Estilo del mapa",
"mapWithFilesDeleted": "Solicitud de mapa offline (y archivos asociados) eliminada",
"maximumZoomLevel": "Nivel máximo de zoom",
"metadata": "Metadatos",
"noCoordinatesProvided": "No se proporcionaron coordenadas",
Expand All @@ -45,6 +48,7 @@
"pleaseGenerateANewMap": "Por favor, genera un nuevo mapa",
"processing": "Procesando",
"render": "Renderizar",
"renderingMap": "Renderizando mapa...",
"requestedOn": "Solicitado en",
"resubmit": "Reenviar",
"status": "Estado",
Expand Down
Loading