Browse Source

add support for deep-link query parameters

pull/139/head
Trent Larson 2 days ago
parent
commit
e9a8a3c1e7
  1. 64
      src/services/deepLinks.ts
  2. 42
      src/views/DeepLinkRedirectView.vue

64
src/services/deepLinks.ts

@ -115,7 +115,7 @@ export class DeepLinkHandler {
const [path, queryString] = parts[1].split("?"); const [path, queryString] = parts[1].split("?");
const [routePath, ...pathParams] = path.split("/"); const [routePath, ...pathParams] = path.split("/");
// logger.log( // logger.info(
// "[DeepLink] Debug:", // "[DeepLink] Debug:",
// "Route Path:", // "Route Path:",
// routePath, // routePath,
@ -150,37 +150,6 @@ export class DeepLinkHandler {
return { path: routePath, params, query }; return { path: routePath, params, query };
} }
/**
* Processes incoming deep links and routes them appropriately.
* Handles validation, error handling, and routing to the correct view.
*
* @param url - The deep link URL to process
* @throws {DeepLinkError} If URL processing fails
*/
async handleDeepLink(url: string): Promise<void> {
try {
logConsoleAndDb("[DeepLink] Processing URL: " + url, false);
const { path, params, query } = this.parseDeepLink(url);
// Ensure params is always a Record<string,string> by converting undefined to empty string
const sanitizedParams = Object.fromEntries(
Object.entries(params).map(([key, value]) => [key, value ?? ""]),
);
await this.validateAndRoute(path, sanitizedParams, query);
} catch (error) {
const deepLinkError = error as DeepLinkError;
logConsoleAndDb(
`[DeepLink] Error (${deepLinkError.code}): ${deepLinkError.message}`,
true,
);
throw {
code: deepLinkError.code || "UNKNOWN_ERROR",
message: deepLinkError.message,
details: deepLinkError.details,
};
}
}
/** /**
* Routes the deep link to appropriate view with validated parameters. * Routes the deep link to appropriate view with validated parameters.
* Validates route and parameters using Zod schemas before routing. * Validates route and parameters using Zod schemas before routing.
@ -256,4 +225,35 @@ export class DeepLinkHandler {
}; };
} }
} }
/**
* Processes incoming deep links and routes them appropriately.
* Handles validation, error handling, and routing to the correct view.
*
* @param url - The deep link URL to process
* @throws {DeepLinkError} If URL processing fails
*/
async handleDeepLink(url: string): Promise<void> {
try {
logConsoleAndDb("[DeepLink] Processing URL: " + url, false);
const { path, params, query } = this.parseDeepLink(url);
// Ensure params is always a Record<string,string> by converting undefined to empty string
const sanitizedParams = Object.fromEntries(
Object.entries(params).map(([key, value]) => [key, value ?? ""]),
);
await this.validateAndRoute(path, sanitizedParams, query);
} catch (error) {
const deepLinkError = error as DeepLinkError;
logConsoleAndDb(
`[DeepLink] Error (${deepLinkError.code}): ${deepLinkError.message}`,
true,
);
throw {
code: deepLinkError.code || "UNKNOWN_ERROR",
message: deepLinkError.message,
details: deepLinkError.details,
};
}
}
} }

42
src/views/DeepLinkRedirectView.vue

@ -122,17 +122,31 @@ export default class DeepLinkRedirectView extends Vue {
// If pathParam is an array (catch-all parameter), join it // If pathParam is an array (catch-all parameter), join it
const fullPath = Array.isArray(pathParam) ? pathParam.join("/") : pathParam; const fullPath = Array.isArray(pathParam) ? pathParam.join("/") : pathParam;
this.destinationUrl = fullPath;
this.deepLinkUrl = `timesafari://${fullPath}`; // Get query parameters from the route
this.webUrl = `${APP_SERVER}/${fullPath}`; const queryParams = this.$route.query;
// Log for debugging // Build query string if there are query parameters
logger.info("Deep link processing:", { let queryString = "";
fullPath, if (Object.keys(queryParams).length > 0) {
deepLinkUrl: this.deepLinkUrl, const searchParams = new URLSearchParams();
webUrl: this.webUrl, Object.entries(queryParams).forEach(([key, value]) => {
userAgent: this.userAgent, if (value !== undefined && value !== null) {
const stringValue = Array.isArray(value) ? value[0] : value;
if (stringValue !== null && stringValue !== undefined) {
searchParams.append(key, stringValue);
}
}
}); });
queryString = "?" + searchParams.toString();
}
// Combine path with query parameters
const fullPathWithQuery = fullPath + queryString;
this.destinationUrl = fullPathWithQuery;
this.deepLinkUrl = `timesafari://${fullPathWithQuery}`;
this.webUrl = `${APP_SERVER}/${fullPathWithQuery}`;
this.isDevelopment = process.env.NODE_ENV !== "production"; this.isDevelopment = process.env.NODE_ENV !== "production";
this.userAgent = navigator.userAgent; this.userAgent = navigator.userAgent;
@ -147,13 +161,6 @@ export default class DeepLinkRedirectView extends Vue {
return; return;
} }
logger.info("Attempting deep link redirect:", {
deepLinkUrl: this.deepLinkUrl,
webUrl: this.webUrl,
isMobile: this.isMobile,
userAgent: this.userAgent,
});
try { try {
// For mobile, try the deep link URL; for desktop, use the web URL // For mobile, try the deep link URL; for desktop, use the web URL
const redirectUrl = this.isMobile ? this.deepLinkUrl : this.webUrl; const redirectUrl = this.isMobile ? this.deepLinkUrl : this.webUrl;
@ -170,7 +177,6 @@ export default class DeepLinkRedirectView extends Vue {
document.body.appendChild(link); document.body.appendChild(link);
link.click(); link.click();
document.body.removeChild(link); document.body.removeChild(link);
logger.info("Fallback link click completed");
} catch (error) { } catch (error) {
logger.error( logger.error(
"Fallback deep link failed: " + errorStringForLog(error), "Fallback deep link failed: " + errorStringForLog(error),

Loading…
Cancel
Save