forked from jsnbuchanan/crowd-funder-for-time-pwa
chore: reverting files to conform to master
This commit is contained in:
@@ -403,7 +403,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 35;
|
CURRENT_PROJECT_VERSION = 37;
|
||||||
DEVELOPMENT_TEAM = GM3FS5JQPH;
|
DEVELOPMENT_TEAM = GM3FS5JQPH;
|
||||||
ENABLE_APP_SANDBOX = NO;
|
ENABLE_APP_SANDBOX = NO;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
@@ -413,7 +413,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.2;
|
MARKETING_VERSION = 1.0.4;
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = app.timesafari;
|
PRODUCT_BUNDLE_IDENTIFIER = app.timesafari;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
@@ -430,7 +430,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 35;
|
CURRENT_PROJECT_VERSION = 37;
|
||||||
DEVELOPMENT_TEAM = GM3FS5JQPH;
|
DEVELOPMENT_TEAM = GM3FS5JQPH;
|
||||||
ENABLE_APP_SANDBOX = NO;
|
ENABLE_APP_SANDBOX = NO;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
@@ -440,7 +440,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.2;
|
MARKETING_VERSION = 1.0.4;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = app.timesafari;
|
PRODUCT_BUNDLE_IDENTIFIER = app.timesafari;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
||||||
|
|||||||
@@ -42,114 +42,75 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { computed, onMounted } from "vue";
|
||||||
import { RouteLocationNormalizedLoaded, Router } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import {
|
import {
|
||||||
VALID_DEEP_LINK_ROUTES,
|
VALID_DEEP_LINK_ROUTES,
|
||||||
deepLinkSchemas,
|
deepLinkSchemas,
|
||||||
} from "../interfaces/deepLinks";
|
} from "../interfaces/deepLinks";
|
||||||
|
import { logConsoleAndDb } from "../db/databaseUtil";
|
||||||
import { logger } from "../utils/logger";
|
import { logger } from "../utils/logger";
|
||||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
|
||||||
|
|
||||||
/**
|
const route = useRoute();
|
||||||
* DeepLinkErrorView - Displays error information for invalid deep links
|
const router = useRouter();
|
||||||
*
|
// an object with the route as the key and the first param name as the value
|
||||||
* This view shows detailed error information when a user follows an invalid
|
const deepLinkSchemaKeys = Object.fromEntries(
|
||||||
* 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]) => {
|
Object.entries(deepLinkSchemas).map(([route, schema]) => {
|
||||||
const param = Object.keys(schema.shape)[0];
|
const param = Object.keys(schema.shape)[0];
|
||||||
return [route, param];
|
return [route, param];
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
// Computed properties for error information
|
// Extract error information from query params
|
||||||
get errorCode(): string {
|
const errorCode = computed(
|
||||||
return (this.route.query.errorCode as string) || "UNKNOWN_ERROR";
|
() => (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;
|
||||||
|
|
||||||
get errorMessage(): string {
|
// Format the path and include any parameters
|
||||||
return (
|
const formattedPath = computed(() => {
|
||||||
(this.route.query.errorMessage as string) ||
|
if (!originalPath.value) return "";
|
||||||
"The deep link you followed is invalid or not supported."
|
const path = originalPath.value.replace(/^\/+/, "");
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
// Log for debugging
|
||||||
logger.log(
|
logger.log(
|
||||||
"[DeepLinkError] Original Path:",
|
"[DeepLinkError] Original Path:",
|
||||||
this.originalPath,
|
originalPath.value,
|
||||||
"Route Params:",
|
"Route Params:",
|
||||||
this.route.params,
|
route.params,
|
||||||
"Route Query:",
|
"Route Query:",
|
||||||
this.route.query,
|
route.query,
|
||||||
);
|
);
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
});
|
||||||
|
|
||||||
// Navigation methods
|
// Navigation methods
|
||||||
goHome(): void {
|
const goHome = () => router.replace({ name: "home" });
|
||||||
this.router.replace({ name: "home" });
|
const reportIssue = () => {
|
||||||
}
|
|
||||||
|
|
||||||
reportIssue(): void {
|
|
||||||
// Open a support form or email
|
// Open a support form or email
|
||||||
window.open(
|
window.open(
|
||||||
"mailto:support@timesafari.app?subject=Invalid Deep Link&body=" +
|
"mailto:support@timesafari.app?subject=Invalid Deep Link&body=" +
|
||||||
encodeURIComponent(
|
encodeURIComponent(
|
||||||
`I encountered an error with a deep link: timesafari://${this.originalPath}\nError: ${this.errorMessage}`,
|
`I encountered an error with a deep link: timesafari://${originalPath.value}\nError: ${errorMessage.value}`,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Lifecycle hook
|
// Log the error for analytics
|
||||||
mounted(): void {
|
onMounted(() => {
|
||||||
// Log the error for analytics
|
logConsoleAndDb(
|
||||||
this.$logAndConsole(
|
`[DeepLinkError] Error page displayed for path: ${originalPath.value}, code: ${errorCode.value}, params: ${JSON.stringify(route.params)}, query: ${JSON.stringify(route.query)}`,
|
||||||
`[DeepLinkError] Error page displayed for path: ${this.originalPath}, code: ${this.errorCode}, params: ${JSON.stringify(this.route.params)}, query: ${JSON.stringify(this.route.query)}`,
|
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -102,35 +102,9 @@ import { RouteLocationNormalizedLoaded, Router } from "vue-router";
|
|||||||
import { APP_SERVER } from "@/constants/app";
|
import { APP_SERVER } from "@/constants/app";
|
||||||
import { logger } from "@/utils/logger";
|
import { logger } from "@/utils/logger";
|
||||||
import { errorStringForLog } from "@/libs/endorserServer";
|
import { errorStringForLog } from "@/libs/endorserServer";
|
||||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
|
||||||
|
|
||||||
/**
|
@Component({})
|
||||||
* DeepLinkRedirectView Component
|
|
||||||
*
|
|
||||||
* Handles deep link redirection from web to the Time Safari mobile app.
|
|
||||||
* Provides platform-specific redirection logic and fallback options.
|
|
||||||
*
|
|
||||||
* Features:
|
|
||||||
* - Deep link redirection to mobile app
|
|
||||||
* - Platform detection (iOS/Android/Desktop)
|
|
||||||
* - Web fallback for desktop users
|
|
||||||
* - Manual link options for failed redirects
|
|
||||||
* - Development debugging information
|
|
||||||
*
|
|
||||||
* Deep Link Format:
|
|
||||||
* - Mobile: timesafari://[path]?[query]
|
|
||||||
* - Web: https://timesafari.app/[path]?[query]
|
|
||||||
*
|
|
||||||
* Route Parameters:
|
|
||||||
* - path: Catch-all parameter for the destination path
|
|
||||||
* - query: Query parameters to pass to the app
|
|
||||||
*
|
|
||||||
* @author Matthew Raymer
|
|
||||||
* @since 2025-07-21
|
|
||||||
*/
|
|
||||||
@Component({
|
|
||||||
mixins: [PlatformServiceMixin],
|
|
||||||
})
|
|
||||||
export default class DeepLinkRedirectView extends Vue {
|
export default class DeepLinkRedirectView extends Vue {
|
||||||
$router!: Router;
|
$router!: Router;
|
||||||
$route!: RouteLocationNormalizedLoaded;
|
$route!: RouteLocationNormalizedLoaded;
|
||||||
@@ -140,11 +114,8 @@ export default class DeepLinkRedirectView extends Vue {
|
|||||||
webUrl: string | null = null; // web link, eg "https://timesafari.app/..."
|
webUrl: string | null = null; // web link, eg "https://timesafari.app/..."
|
||||||
isDevelopment: boolean = false;
|
isDevelopment: boolean = false;
|
||||||
userAgent: string = "";
|
userAgent: string = "";
|
||||||
|
private platformService = PlatformServiceFactory.getInstance();
|
||||||
|
|
||||||
/**
|
|
||||||
* Component lifecycle hook - initializes deep link redirection
|
|
||||||
* Parses route parameters and sets up redirect URLs
|
|
||||||
*/
|
|
||||||
mounted() {
|
mounted() {
|
||||||
// Get the path from the route parameter (catch-all parameter)
|
// Get the path from the route parameter (catch-all parameter)
|
||||||
const pathParam = this.$route.params.path;
|
const pathParam = this.$route.params.path;
|
||||||
@@ -183,10 +154,6 @@ export default class DeepLinkRedirectView extends Vue {
|
|||||||
this.openDeepLink();
|
this.openDeepLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to open the deep link URL
|
|
||||||
* Uses multiple fallback methods for maximum compatibility
|
|
||||||
*/
|
|
||||||
private openDeepLink() {
|
private openDeepLink() {
|
||||||
if (!this.deepLinkUrl || !this.webUrl) {
|
if (!this.deepLinkUrl || !this.webUrl) {
|
||||||
this.pageError =
|
this.pageError =
|
||||||
@@ -225,11 +192,6 @@ export default class DeepLinkRedirectView extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles deep link button click
|
|
||||||
* Prevents default behavior and manually triggers deep link
|
|
||||||
* @param event - Click event
|
|
||||||
*/
|
|
||||||
private handleDeepLinkClick(event: Event) {
|
private handleDeepLinkClick(event: Event) {
|
||||||
if (!this.deepLinkUrl) return;
|
if (!this.deepLinkUrl) return;
|
||||||
|
|
||||||
@@ -239,16 +201,11 @@ export default class DeepLinkRedirectView extends Vue {
|
|||||||
this.openDeepLink();
|
this.openDeepLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles web fallback button click
|
|
||||||
* Uses platform-specific behavior for opening web links
|
|
||||||
* @param event - Click event
|
|
||||||
*/
|
|
||||||
private handleWebFallbackClick(event: Event) {
|
private handleWebFallbackClick(event: Event) {
|
||||||
if (!this.webUrl) return;
|
if (!this.webUrl) return;
|
||||||
|
|
||||||
// Get platform capabilities using mixin
|
// Get platform capabilities
|
||||||
const capabilities = this.platformCapabilities;
|
const capabilities = this.platformService.getCapabilities();
|
||||||
|
|
||||||
// For mobile, try to open in a new tab/window
|
// For mobile, try to open in a new tab/window
|
||||||
if (capabilities.isMobile) {
|
if (capabilities.isMobile) {
|
||||||
@@ -258,30 +215,13 @@ export default class DeepLinkRedirectView extends Vue {
|
|||||||
// For desktop, let the default behavior happen (opens in same tab)
|
// For desktop, let the default behavior happen (opens in same tab)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== COMPUTED PROPERTIES =====
|
// Computed properties for template
|
||||||
|
|
||||||
/**
|
|
||||||
* Platform capabilities accessor
|
|
||||||
* Provides cached access to platform capabilities
|
|
||||||
*/
|
|
||||||
get platformCapabilities() {
|
|
||||||
return this.platformService.getCapabilities();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if the current platform is mobile
|
|
||||||
* Uses PlatformServiceMixin for platform detection
|
|
||||||
*/
|
|
||||||
get isMobile(): boolean {
|
get isMobile(): boolean {
|
||||||
return this.platformCapabilities.isMobile;
|
return this.platformService.getCapabilities().isMobile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if the current platform is iOS
|
|
||||||
* Uses PlatformServiceMixin for platform detection
|
|
||||||
*/
|
|
||||||
get isIOS(): boolean {
|
get isIOS(): boolean {
|
||||||
return this.platformCapabilities.isIOS;
|
return this.platformService.getCapabilities().isIOS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user