const WECOM_WEBVIEW_PATTERN = /(wxwork|wecom|wechatwork)/i; const ENTERPRISE_IM_PATTERN = /(wxwork|wecom|wechatwork|dingtalk|aliapp\(dingtalk\))/i; export function canUseWindow() { return typeof window !== "undefined"; } export function matchesMedia(query: string) { return canUseWindow() && typeof window.matchMedia === "function" && window.matchMedia(query).matches; } export function readUserAgent() { return canUseWindow() ? window.navigator.userAgent : ""; } export function isWecomWebView(userAgent = readUserAgent()) { return WECOM_WEBVIEW_PATTERN.test(userAgent); } export function isEnterpriseMessengerContainer(userAgent = readUserAgent()) { return ENTERPRISE_IM_PATTERN.test(userAgent); } export function isTouchSmallScreen() { if (!canUseWindow()) { return false; } return window.navigator.maxTouchPoints > 0 && matchesMedia("(max-width: 768px)"); } export function shouldPreferMobileWorkplace() { return isEnterpriseMessengerContainer() || isTouchSmallScreen(); } export function resolveDefaultWorkspacePath() { return shouldPreferMobileWorkplace() ? "/mobile" : "/portal"; } function encodeSegment(value: string) { return encodeURIComponent(value); } export function resolveMobileEquivalentPath(pathname: string, search = "") { const normalizedPath = pathname.replace(/\/+$/, "") || "/"; const searchParams = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search); if (normalizedPath === "/" || normalizedPath === "/portal" || normalizedPath === "/dashboard") { return "/mobile"; } if (normalizedPath === "/notifications") { return "/mobile/notifications"; } if (normalizedPath === "/settings/profile") { return "/mobile/profile"; } if (normalizedPath === "/reimbursements" || normalizedPath === "/reimbursements/dashboard") { return "/mobile/reimbursements"; } const reimbursementPrintMatch = normalizedPath.match(/^\/reimbursements\/([^/]+)\/print$/); if (reimbursementPrintMatch?.[1]) { return `/mobile/reimbursements/${encodeSegment(reimbursementPrintMatch[1])}`; } const reimbursementDetailMatch = normalizedPath.match(/^\/reimbursements\/([^/]+)$/); if (reimbursementDetailMatch?.[1]) { return `/mobile/reimbursements/${encodeSegment(reimbursementDetailMatch[1])}`; } if (normalizedPath === "/leave-requests") { const leaveRequestId = searchParams.get("highlight") ?? searchParams.get("id") ?? searchParams.get("requestId"); if (leaveRequestId) { return `/mobile/leave/${encodeSegment(leaveRequestId)}`; } const action = searchParams.get("action") ?? searchParams.get("view"); if (action === "create" || action === "form") { return "/mobile/leave?view=form"; } return "/mobile/leave"; } if (normalizedPath === "/invoice-pool") { return "/mobile/capture"; } if (normalizedPath === "/attendance") { return "/mobile/attendance"; } const workflowTaskMatch = normalizedPath.match(/^\/workflow\/tasks\/([^/]+)$/); if (workflowTaskMatch?.[1]) { return `/mobile/approvals/${encodeSegment(workflowTaskMatch[1])}`; } if (normalizedPath === "/workflow/tasks") { return "/mobile/approvals"; } if (normalizedPath === "/assets" || normalizedPath.startsWith("/assets/") || normalizedPath === "/inventory-checks") { return "/mobile/assets/scan"; } if ( normalizedPath.startsWith("/system") || normalizedPath.startsWith("/people") || normalizedPath.startsWith("/organization") || normalizedPath.startsWith("/payroll") || normalizedPath.startsWith("/performance") ) { return "/mobile/me"; } if ( normalizedPath.startsWith("/projects") || normalizedPath.startsWith("/contracts-registry") || normalizedPath.startsWith("/travel-requests") || normalizedPath.startsWith("/ap-operations") || normalizedPath.startsWith("/weekly-reports") || normalizedPath.startsWith("/todos") || normalizedPath.startsWith("/team") || normalizedPath.startsWith("/budgets") || normalizedPath.startsWith("/announcements") || normalizedPath.startsWith("/delegations") ) { return "/mobile"; } if (normalizedPath === "/payment-batches") { return `/mobile/payment-batches${search}`; } if (normalizedPath === "/purchase-requests") { const purchaseRequestId = searchParams.get("highlight") ?? searchParams.get("id") ?? searchParams.get("requestId"); if (purchaseRequestId) { return `/mobile/purchase-requests/${encodeSegment(purchaseRequestId)}`; } return "/mobile/purchase-requests"; } const purchaseRequestDetailMatch = normalizedPath.match(/^\/purchase-requests\/([^/]+)$/); if (purchaseRequestDetailMatch?.[1]) { return `/mobile/purchase-requests/${encodeSegment(purchaseRequestDetailMatch[1])}`; } return search ? `${pathname}${search}` : pathname; }