mirror of
https://github.com/Novaloop-AG/healthchat-web.git
synced 2026-10-31 16:23:03 +00:00
fix(mobile-guide): German HealthChat guide for phones, proven in Chromium
Phones and tablets were bounced to the healthchat.ch website, where the visitor had no way back into the app. They now land on the mobile guide again, which pointed at Element X and spoke English while the rest of HealthChat web is German. The guide carries the HealthChat store links and German copy as static HTML, not only via JS: Safari reads the Smart App Banner meta tag at parse time. A charset meta is required now that the page has umlauts, since nginx sends text/html without one. Step 2 and the F-Droid line stay hidden because HealthChat has neither a mobile.element.io deep link nor an F-Droid build. Verified in Chromium at phone width with iPhone and Android user agents: redirect, store links, the way back via the cookie, and the no-JS view.
This commit is contained in:
@@ -12,7 +12,7 @@ import ToastStore from "../stores/ToastStore";
|
||||
import SdkConfig from "../SdkConfig";
|
||||
|
||||
const onAccept = (): void => {
|
||||
window.location.href = "https://healthchat.ch";
|
||||
window.location.href = "mobile_guide/";
|
||||
};
|
||||
|
||||
const onReject = (): void => {
|
||||
|
||||
@@ -149,7 +149,7 @@ async function start(): Promise<void> {
|
||||
const isAndroid = /Android/.test(navigator.userAgent);
|
||||
if (isIos || isAndroid) {
|
||||
if (document.cookie.indexOf("element_mobile_redirect_to_guide=false") === -1) {
|
||||
window.location.href = "https://healthchat.ch";
|
||||
window.location.href = "mobile_guide/";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,31 +20,31 @@
|
||||
<feGaussianBlur stdDeviation="16.3415" result="effect1_foregroundBlur_382_1634"/>
|
||||
</filter>
|
||||
<linearGradient id="paint0_linear_382_1634" x1="141.636" y1="133.796" x2="141.636" y2="32.6829" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#062993"/>
|
||||
<stop offset="0.040404" stop-color="#02389D"/>
|
||||
<stop offset="0.0808081" stop-color="#0045A6"/>
|
||||
<stop offset="0.121212" stop-color="#0051AD"/>
|
||||
<stop offset="0.161616" stop-color="#005DB4"/>
|
||||
<stop offset="0.20202" stop-color="#0069BA"/>
|
||||
<stop offset="0.242424" stop-color="#0075BB"/>
|
||||
<stop offset="0.282828" stop-color="#0081BB"/>
|
||||
<stop offset="0.323232" stop-color="#008CB9"/>
|
||||
<stop offset="0.363636" stop-color="#0098B7"/>
|
||||
<stop offset="0.40404" stop-color="#00A3B3"/>
|
||||
<stop offset="0.444444" stop-color="#00AEAD"/>
|
||||
<stop offset="0.484848" stop-color="#00B8A4"/>
|
||||
<stop offset="0.525253" stop-color="#00C2A0"/>
|
||||
<stop offset="0.565657" stop-color="#00CC99"/>
|
||||
<stop offset="0.606061" stop-color="#3AD396"/>
|
||||
<stop offset="0.646465" stop-color="#5DD898"/>
|
||||
<stop offset="0.686869" stop-color="#79DD99"/>
|
||||
<stop offset="0.727273" stop-color="#92E29B"/>
|
||||
<stop offset="0.767677" stop-color="#A8E69F"/>
|
||||
<stop offset="0.808081" stop-color="#BBEAA5"/>
|
||||
<stop offset="0.848485" stop-color="#CDEEAE"/>
|
||||
<stop offset="0.888889" stop-color="#DCF2B9"/>
|
||||
<stop offset="0.929293" stop-color="#EAF6C7"/>
|
||||
<stop offset="0.969697" stop-color="#F5FBD5"/>
|
||||
<stop stop-color="#12325C"/>
|
||||
<stop offset="0.040404" stop-color="#143561"/>
|
||||
<stop offset="0.0808081" stop-color="#153966"/>
|
||||
<stop offset="0.121212" stop-color="#173C6C"/>
|
||||
<stop offset="0.161616" stop-color="#194071"/>
|
||||
<stop offset="0.20202" stop-color="#1A4376"/>
|
||||
<stop offset="0.242424" stop-color="#1C467B"/>
|
||||
<stop offset="0.282828" stop-color="#1D4A80"/>
|
||||
<stop offset="0.323232" stop-color="#1F4D85"/>
|
||||
<stop offset="0.363636" stop-color="#225187"/>
|
||||
<stop offset="0.40404" stop-color="#255588"/>
|
||||
<stop offset="0.444444" stop-color="#28588A"/>
|
||||
<stop offset="0.484848" stop-color="#2B5C8B"/>
|
||||
<stop offset="0.525253" stop-color="#2E608D"/>
|
||||
<stop offset="0.565657" stop-color="#31638E"/>
|
||||
<stop offset="0.606061" stop-color="#346790"/>
|
||||
<stop offset="0.646465" stop-color="#3B6D93"/>
|
||||
<stop offset="0.686869" stop-color="#527E9F"/>
|
||||
<stop offset="0.727273" stop-color="#698FAB"/>
|
||||
<stop offset="0.767677" stop-color="#81A0B8"/>
|
||||
<stop offset="0.808081" stop-color="#98B1C4"/>
|
||||
<stop offset="0.848485" stop-color="#AFC2D0"/>
|
||||
<stop offset="0.888889" stop-color="#C6D3DC"/>
|
||||
<stop offset="0.929293" stop-color="#DEE4E9"/>
|
||||
<stop offset="0.969697" stop-color="#F5F5F5"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_382_1634">
|
||||
<rect width="375" height="178" fill="white"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
@@ -3,11 +3,12 @@
|
||||
Please note: This page is similar to the one at mobile.element.io so any changes made here can potentially
|
||||
be applied to that site as well. They still share the mobile-apps.ts file for updating the app metadata.
|
||||
-->
|
||||
<html lang="en">
|
||||
<html lang="de">
|
||||
<head>
|
||||
<title>Element Mobile Guide</title>
|
||||
<meta charset="utf-8" />
|
||||
<title>HealthChat für Smartphone und Tablet</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="apple-itunes-app" content="app-id=id1631335820" />
|
||||
<meta name="apple-itunes-app" content="app-id=id6743060078" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -19,10 +20,15 @@
|
||||
<header>
|
||||
<div class="mx_HomePage_header">
|
||||
<div>
|
||||
<img src="./assets/element-logo.svg" alt="Element Logo" width="148px" height="32px" />
|
||||
<img
|
||||
src="../themes/element/img/logos/element-logo.png"
|
||||
alt="HealthChat Logo"
|
||||
width="32px"
|
||||
height="32px"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<p id="header_title">Join Element.</p>
|
||||
<p id="header_title">HealthChat auf dem Smartphone</p>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
@@ -31,8 +37,8 @@
|
||||
<main>
|
||||
<div class="mx_HomePage_col mx_Spacer">
|
||||
<p>
|
||||
The <a id="back_to_element_button" href="#" class="mx_DesktopLink">desktop site</a> does
|
||||
<b>not</b> work on mobile, please download the app.
|
||||
Die Web-Version ist für den Desktop gedacht und funktioniert auf Smartphone und Tablet
|
||||
<b>nicht</b>. Für Smartphone und Tablet gibt es die HealthChat-App.
|
||||
</p>
|
||||
</div>
|
||||
<div class="mx_HomePage_col mx_Spacer">
|
||||
@@ -41,44 +47,38 @@
|
||||
<span>1</span>
|
||||
</div>
|
||||
<div>
|
||||
<h1 id="step1_heading">Download Element</h1>
|
||||
<h1 id="step1_heading">HealthChat-App laden</h1>
|
||||
<div class="mx_StoreLinks">
|
||||
<a
|
||||
href="https://apps.apple.com/app/element-x-secure-chat-call/id1631335820"
|
||||
href="https://apps.apple.com/ch/app/healthchat/id6743060078"
|
||||
target="_blank"
|
||||
class="mx_StoreBadge"
|
||||
id="app_store_link"
|
||||
>
|
||||
<img
|
||||
src="./assets/app-store-badge.svg"
|
||||
alt="Download on the App Store."
|
||||
alt="Im App Store laden."
|
||||
width="120px"
|
||||
height="40px"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://play.google.com/store/apps/details?id=io.element.android.x"
|
||||
href="https://play.google.com/store/apps/details?id=ch.healthchat.element"
|
||||
target="_blank"
|
||||
class="mx_StoreBadge"
|
||||
id="play_store_link"
|
||||
>
|
||||
<img
|
||||
src="./assets/google-play-badge.svg"
|
||||
alt="Get it on Google Play."
|
||||
alt="Jetzt bei Google Play."
|
||||
width="135px"
|
||||
height="40px"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<p id="f_droid_section">
|
||||
Also available on
|
||||
<a
|
||||
href="https://f-droid.org/packages/io.element.android.x"
|
||||
target="_blank"
|
||||
class="mx_ClearDecoration"
|
||||
id="f_droid_link"
|
||||
>F-Droid</a
|
||||
>
|
||||
<p id="f_droid_section" style="display: none">
|
||||
Auch verfügbar auf
|
||||
<a href="#" target="_blank" class="mx_ClearDecoration" id="f_droid_link">F-Droid</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -89,12 +89,19 @@
|
||||
<span>2</span>
|
||||
</div>
|
||||
<div>
|
||||
<h1>Come back here to sign in</h1>
|
||||
<p id="step2_description">This will set up your app</p>
|
||||
<a class="mx_Button" id="deep_link_button" href="#">Sign in</a>
|
||||
<h1>Danach hier anmelden</h1>
|
||||
<p id="step2_description">Damit wird die App eingerichtet</p>
|
||||
<a class="mx_Button" id="deep_link_button" href="#">Anmelden</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mx_HomePage_col mx_Spacer">
|
||||
<p>
|
||||
<a id="back_to_element_button" href="#" class="mx_DesktopLink"
|
||||
>Trotzdem die Web-Version öffnen</a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ function onBackToElementClick(): void {
|
||||
// NEVER pass user-controlled content to this function! Hardcoded strings only please.
|
||||
function renderConfigError(message: string): void {
|
||||
const contactMsg =
|
||||
"If this is unexpected, please contact your system administrator " + "or technical support representative.";
|
||||
message = `<h2>Error loading Element</h2><p>${message}</p><p>${contactMsg}</p>`;
|
||||
"Falls das unerwartet ist, bitte den Systemadministrator " + "oder den technischen Support kontaktieren.";
|
||||
message = `<h2>HealthChat konnte nicht geladen werden</h2><p>${message}</p><p>${contactMsg}</p>`;
|
||||
|
||||
const toHide = document.getElementsByClassName("mx_HomePage_container");
|
||||
const errorContainers = document.getElementsByClassName(
|
||||
@@ -59,12 +59,12 @@ async function initPage(): Promise<void> {
|
||||
const incompatibleOptions = [wkConfig, serverName, defaultHsUrl].filter((i) => !!i);
|
||||
if (defaultHsUrl && (wkConfig || serverName)) {
|
||||
return renderConfigError(
|
||||
"Invalid configuration: a default_hs_url can't be specified along with default_server_name " +
|
||||
"or default_server_config",
|
||||
"Ungültige Konfiguration: default_hs_url kann nicht zusammen mit default_server_name " +
|
||||
"oder default_server_config angegeben werden",
|
||||
);
|
||||
}
|
||||
if (incompatibleOptions.length < 1) {
|
||||
return renderConfigError("Invalid configuration: no default server specified.");
|
||||
return renderConfigError("Ungültige Konfiguration: kein Standard-Server angegeben.");
|
||||
}
|
||||
|
||||
let hsUrl: string | undefined;
|
||||
@@ -100,7 +100,7 @@ async function initPage(): Promise<void> {
|
||||
}
|
||||
} else {
|
||||
logger.error(e);
|
||||
return renderConfigError("Unable to fetch homeserver configuration");
|
||||
return renderConfigError("Homeserver-Konfiguration konnte nicht geladen werden");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,7 +111,7 @@ async function initPage(): Promise<void> {
|
||||
}
|
||||
|
||||
if (!hsUrl) {
|
||||
return renderConfigError("Unable to locate homeserver");
|
||||
return renderConfigError("Homeserver konnte nicht gefunden werden");
|
||||
}
|
||||
|
||||
if (hsUrl && !hsUrl.endsWith("/")) hsUrl += "/";
|
||||
@@ -131,7 +131,7 @@ async function initPage(): Promise<void> {
|
||||
// Not part of updateMobilePage as the link is only shown on mobile_guide and not on mobile.element.io
|
||||
document.getElementById("back_to_element_button")!.onclick = onBackToElementClick;
|
||||
|
||||
updateMobilePage(metadata, deepLinkUrl, serverName ?? hsUrl);
|
||||
updateMobilePage(metadata, deepLinkUrl);
|
||||
}
|
||||
|
||||
void initPage();
|
||||
|
||||
@@ -38,12 +38,11 @@ export const mobileApps: Record<MobileAppVariant, MobileAppMetadata> = {
|
||||
isProApp: false,
|
||||
},
|
||||
[MobileAppVariant.X]: {
|
||||
name: "Element X",
|
||||
appleAppId: "id1631335820",
|
||||
appStoreUrl: "https://apps.apple.com/app/element-x-secure-chat-call/id1631335820",
|
||||
playStoreUrl: "https://play.google.com/store/apps/details?id=io.element.android.x",
|
||||
fDroidUrl: "https://f-droid.org/packages/io.element.android.x",
|
||||
deepLinkPath: "/element",
|
||||
name: "HealthChat",
|
||||
appleAppId: "id6743060078",
|
||||
appStoreUrl: "https://apps.apple.com/ch/app/healthchat/id6743060078",
|
||||
playStoreUrl: "https://play.google.com/store/apps/details?id=ch.healthchat.element",
|
||||
deepLinkPath: "",
|
||||
usesLegacyDeepLink: false,
|
||||
isProApp: false,
|
||||
},
|
||||
@@ -58,18 +57,17 @@ export const mobileApps: Record<MobileAppVariant, MobileAppMetadata> = {
|
||||
},
|
||||
};
|
||||
|
||||
export function updateMobilePage(metadata: MobileAppMetadata, deepLinkUrl: string, server: string | undefined): void {
|
||||
export function updateMobilePage(metadata: MobileAppMetadata, deepLinkUrl: string): void {
|
||||
const appleMeta = document.querySelector('meta[name="apple-itunes-app"]') as Element;
|
||||
appleMeta.setAttribute("content", `app-id=${metadata.appleAppId}`);
|
||||
|
||||
if (server) {
|
||||
(document.getElementById("header_title") as HTMLHeadingElement).innerText = `Join ${server} on Element`;
|
||||
}
|
||||
(document.getElementById("header_title") as HTMLHeadingElement).innerText = `${metadata.name} auf dem Smartphone`;
|
||||
(document.getElementById("app_store_link") as HTMLAnchorElement).href = metadata.appStoreUrl;
|
||||
(document.getElementById("play_store_link") as HTMLAnchorElement).href = metadata.playStoreUrl;
|
||||
|
||||
if (metadata.fDroidUrl) {
|
||||
(document.getElementById("f_droid_link") as HTMLAnchorElement).href = metadata.fDroidUrl;
|
||||
document.getElementById("f_droid_section")!.style.display = "";
|
||||
} else {
|
||||
document.getElementById("f_droid_section")!.style.display = "none";
|
||||
}
|
||||
@@ -77,11 +75,12 @@ export function updateMobilePage(metadata: MobileAppMetadata, deepLinkUrl: strin
|
||||
const step1Heading = document.getElementById("step1_heading")!;
|
||||
step1Heading.innerHTML = step1Heading!.innerHTML.replace("Element", metadata.name);
|
||||
|
||||
// Step 2 is only shown on the mobile guide, not on mobile.element.io
|
||||
if (document.getElementById("step2_container")) {
|
||||
// Step 2 is only shown on the mobile guide, not on mobile.element.io,
|
||||
// and only for apps that offer a sign-in deep link
|
||||
if (document.getElementById("step2_container") && (metadata.deepLinkPath || metadata.usesLegacyDeepLink)) {
|
||||
document.getElementById("step2_container")!.style.display = "block";
|
||||
if (metadata.isProApp) {
|
||||
document.getElementById("step2_description")!.innerHTML = "Use your work email to join";
|
||||
document.getElementById("step2_description")!.innerHTML = "Mit der Arbeits-E-Mail-Adresse anmelden";
|
||||
}
|
||||
(document.getElementById("deep_link_button") as HTMLAnchorElement).href = deepLinkUrl;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user