diff options
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/profile-page.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/profile-page.js | 56 |
1 files changed, 55 insertions, 1 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/profile-page.js b/packages/meshbay-hub/src/meshbay_hub/static/profile-page.js index cd00f03..7c36951 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/profile-page.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/profile-page.js @@ -6,7 +6,7 @@ import { ask } from './ask.js'; import { Icon } from './icon.js'; import * as platform from './platform.js'; import { - hubFetch, HUB, session, setAuth, + hubFetch, HUB, session, setAuth, mirrorBrowserAccess, _storeBundleKey, _loadBundleKey, _storeRecoveryKey, } from './hub-client.js'; @@ -241,6 +241,46 @@ export function ProfilePage({ user, onLogout }) { } }, [rkInput, user]); + // ── Browser access (docs/MESHBAY_DESIGN.md §3.7) ──────────────────────── + // Decided in the desktop application, which keeps the identities: there it + // is a switch, and turning it on is confirmed by the application itself. A + // browser only reads the hub's mirror, to say why it cannot open a group. + const [baNative, setBaNative] = useState(false); + const [baOn, setBaOn] = useState(null); + const [baBusy, setBaBusy] = useState(false); + const [baMsg, setBaMsg] = useState(''); + useEffect(() => { + let gone = false; + (async () => { + const native = await platform.nativeKeys(); + if (gone) return; + setBaNative(native); + if (native) { + const on = await platform.keys.browserAccess(user.userId); + if (!gone) setBaOn(on); + return; + } + try { + const prefs = await hubFetch('/v1/users/me/preferences', { token: user.token }); + if (!gone) setBaOn((prefs || {}).browser_access !== 'off'); + } catch { /* shown as nothing */ } + })(); + return () => { gone = true; }; + }, [user]); + const baSet = useCallback(async (on) => { + setBaBusy(true); + setBaMsg(''); + try { + setBaOn(await platform.keys.setBrowserAccess(user.userId, on)); + await mirrorBrowserAccess(user.token, user.userId); + setBaMsg(t('settings.browser_access_next_open')); + } catch (err) { + setBaMsg(platform.bridgeMessage(err)); + } finally { + setBaBusy(false); + } + }, [user]); + useEffect(() => { hubFetch('/v1/users/me', { token: user.token }) .then(data => { @@ -539,6 +579,20 @@ export function ProfilePage({ user, onLogout }) { </div>`} </div> + ${baOn !== null && (baNative || baOn === false) && html` + <div class="settings-section"> + <h3 class="settings-heading">${t('settings.browser_access')}</h3> + ${baNative ? html` + <p class="settings-hint"> + ${baOn ? t('settings.browser_access_on_hint') : t('settings.browser_access_off_hint')} + </p> + <button class="btn-secondary" disabled=${baBusy} onClick=${() => baSet(!baOn)}> + ${baOn ? t('settings.browser_access_turn_off') : t('settings.browser_access_turn_on')} + </button> + ${baMsg && html`<p class="settings-hint">${baMsg}</p>`} + ` : html`<p class="settings-hint">${t('settings.browser_access_off_in_browser')}</p>`} + </div>`} + <div class="settings-section"> <h3 class="settings-heading">${t('settings.sessions_heading')}</h3> <p class="settings-hint">${t('settings.sign_out_everywhere_hint')}</p> |