|
|
@ -42,114 +42,75 @@ |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script lang="ts"> |
|
|
|
import { Component, Vue } from "vue-facing-decorator"; |
|
|
|
import { RouteLocationNormalizedLoaded, Router } from "vue-router"; |
|
|
|
<script setup lang="ts"> |
|
|
|
import { computed, onMounted } from "vue"; |
|
|
|
import { useRoute, useRouter } from "vue-router"; |
|
|
|
import { |
|
|
|
VALID_DEEP_LINK_ROUTES, |
|
|
|
deepLinkSchemas, |
|
|
|
} from "../interfaces/deepLinks"; |
|
|
|
import { logConsoleAndDb } from "../db/databaseUtil"; |
|
|
|
import { logger } from "../utils/logger"; |
|
|
|
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin"; |
|
|
|
|
|
|
|
/** |
|
|
|
* DeepLinkErrorView - Displays error information for invalid deep links |
|
|
|
* |
|
|
|
* This view shows detailed error information when a user follows an invalid |
|
|
|
* or unsupported deep link. It provides debugging information and allows |
|
|
|
* users to report issues or navigate back to the home page. |
|
|
|
* |
|
|
|
* @author Matthew Raymer |
|
|
|
*/ |
|
|
|
@Component({ |
|
|
|
name: "DeepLinkErrorView", |
|
|
|
mixins: [PlatformServiceMixin], |
|
|
|
}) |
|
|
|
export default class DeepLinkErrorView extends Vue { |
|
|
|
// Route and router access |
|
|
|
get route() { |
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any |
|
|
|
return (this as any).$route as RouteLocationNormalizedLoaded; |
|
|
|
} |
|
|
|
|
|
|
|
get router() { |
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any |
|
|
|
return (this as any).$router as Router; |
|
|
|
} |
|
|
|
|
|
|
|
// Deep link schema keys mapping |
|
|
|
// This is an object with the route as the key and the first param name as the value |
|
|
|
get deepLinkSchemaKeys() { |
|
|
|
return Object.fromEntries( |
|
|
|
Object.entries(deepLinkSchemas).map(([route, schema]) => { |
|
|
|
const param = Object.keys(schema.shape)[0]; |
|
|
|
return [route, param]; |
|
|
|
}), |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
// Computed properties for error information |
|
|
|
get errorCode(): string { |
|
|
|
return (this.route.query.errorCode as string) || "UNKNOWN_ERROR"; |
|
|
|
} |
|
|
|
|
|
|
|
get errorMessage(): string { |
|
|
|
return ( |
|
|
|
(this.route.query.errorMessage as string) || |
|
|
|
"The deep link you followed is invalid or not supported." |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
get originalPath(): string { |
|
|
|
return this.route.query.originalPath as string; |
|
|
|
} |
|
|
|
|
|
|
|
get validRoutes() { |
|
|
|
return VALID_DEEP_LINK_ROUTES; |
|
|
|
} |
|
|
|
|
|
|
|
// Format the path and include any parameters |
|
|
|
get formattedPath(): string { |
|
|
|
if (!this.originalPath) return ""; |
|
|
|
const path = this.originalPath.replace(/^\/+/, ""); |
|
|
|
|
|
|
|
// Log for debugging |
|
|
|
logger.log( |
|
|
|
"[DeepLinkError] Original Path:", |
|
|
|
this.originalPath, |
|
|
|
"Route Params:", |
|
|
|
this.route.params, |
|
|
|
"Route Query:", |
|
|
|
this.route.query, |
|
|
|
); |
|
|
|
|
|
|
|
return path; |
|
|
|
} |
|
|
|
|
|
|
|
// Navigation methods |
|
|
|
goHome(): void { |
|
|
|
this.router.replace({ name: "home" }); |
|
|
|
} |
|
|
|
|
|
|
|
reportIssue(): void { |
|
|
|
// Open a support form or email |
|
|
|
window.open( |
|
|
|
"mailto:support@timesafari.app?subject=Invalid Deep Link&body=" + |
|
|
|
encodeURIComponent( |
|
|
|
`I encountered an error with a deep link: timesafari://${this.originalPath}\nError: ${this.errorMessage}`, |
|
|
|
), |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
// Lifecycle hook |
|
|
|
mounted(): void { |
|
|
|
// Log the error for analytics |
|
|
|
this.$logAndConsole( |
|
|
|
`[DeepLinkError] Error page displayed for path: ${this.originalPath}, code: ${this.errorCode}, params: ${JSON.stringify(this.route.params)}, query: ${JSON.stringify(this.route.query)}`, |
|
|
|
true, |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
const route = useRoute(); |
|
|
|
const router = useRouter(); |
|
|
|
// an object with the route as the key and the first param name as the value |
|
|
|
const deepLinkSchemaKeys = Object.fromEntries( |
|
|
|
Object.entries(deepLinkSchemas).map(([route, schema]) => { |
|
|
|
const param = Object.keys(schema.shape)[0]; |
|
|
|
return [route, param]; |
|
|
|
}), |
|
|
|
); |
|
|
|
|
|
|
|
// Extract error information from query params |
|
|
|
const errorCode = computed( |
|
|
|
() => (route.query.errorCode as string) || "UNKNOWN_ERROR", |
|
|
|
); |
|
|
|
const errorMessage = computed( |
|
|
|
() => |
|
|
|
(route.query.errorMessage as string) || |
|
|
|
"The deep link you followed is invalid or not supported.", |
|
|
|
); |
|
|
|
const originalPath = computed(() => route.query.originalPath as string); |
|
|
|
const validRoutes = VALID_DEEP_LINK_ROUTES; |
|
|
|
|
|
|
|
// Format the path and include any parameters |
|
|
|
const formattedPath = computed(() => { |
|
|
|
if (!originalPath.value) return ""; |
|
|
|
const path = originalPath.value.replace(/^\/+/, ""); |
|
|
|
|
|
|
|
// Log for debugging |
|
|
|
logger.log( |
|
|
|
"[DeepLinkError] Original Path:", |
|
|
|
originalPath.value, |
|
|
|
"Route Params:", |
|
|
|
route.params, |
|
|
|
"Route Query:", |
|
|
|
route.query, |
|
|
|
); |
|
|
|
|
|
|
|
return path; |
|
|
|
}); |
|
|
|
|
|
|
|
// Navigation methods |
|
|
|
const goHome = () => router.replace({ name: "home" }); |
|
|
|
const reportIssue = () => { |
|
|
|
// Open a support form or email |
|
|
|
window.open( |
|
|
|
"mailto:support@timesafari.app?subject=Invalid Deep Link&body=" + |
|
|
|
encodeURIComponent( |
|
|
|
`I encountered an error with a deep link: timesafari://${originalPath.value}\nError: ${errorMessage.value}`, |
|
|
|
), |
|
|
|
); |
|
|
|
}; |
|
|
|
|
|
|
|
// Log the error for analytics |
|
|
|
onMounted(() => { |
|
|
|
logConsoleAndDb( |
|
|
|
`[DeepLinkError] Error page displayed for path: ${originalPath.value}, code: ${errorCode.value}, params: ${JSON.stringify(route.params)}, query: ${JSON.stringify(route.query)}`, |
|
|
|
true, |
|
|
|
); |
|
|
|
}); |
|
|
|
</script> |
|
|
|
|
|
|
|
<style scoped> |
|
|
|