summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static/chat-app-settings.js
blob: 96fc52fc4de214dbaf67ff87d151807d7fd95ffd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import { html, useState, useEffect } from './vendor/htm-preact.js';
import { t } from './i18n.js';
import { ToggleSwitch, useSaver } from './settings-ui.js';
import { FolderPickerField } from './folder-tree.js';

/**
 * Chat's operator settings.
 *
 * Every app's settings pane takes the same props (see `apps.js`): the group's
 * roots and known folders, the node's current answers, a `saveDirectories`
 * bound to this app, and the transport for anything the app alone needs. It
 * owns its drafts and its own busy state, and the page renders it without
 * naming it.
 *
 * The directory here is unlike every other app's. Videos, Music and Photos
 * point at folders they *read*; this is where attachments get *written*, so it
 * has to be on a read-write root. The picker greys out the rest rather than
 * letting the node's refusal arrive after the fact.
 */
function ChatSettings({ roots, dirs, settings, saveDirectories, transport, signFn }) {
  const { busy, msg, run } = useSaver();
  const [directory, setDirectory] = useState(settings.chatDirectory || '');
  const [linkPreview, setLinkPreview] = useState(settings.chatLinkPreview !== false);

  // Re-seeded from the node's answer: another operator may be editing the
  // same group, and their change arrives here as a prop.
  useEffect(() => { setDirectory(settings.chatDirectory || ''); },
            [settings.chatDirectory]);
  useEffect(() => { setLinkPreview(settings.chatLinkPreview !== false); },
            [settings.chatLinkPreview]);

  const noWritable = !(roots || []).some((r) => r.writable);
  const dirty = directory !== (settings.chatDirectory || '');

  return html`
    <div class="app-settings">
      ${noWritable && html`
        <p class="settings-hint">${t('settings_app.chat_no_writable_root')}</p>`}

      <${FolderPickerField}
        label=${t('settings_app.chat_directory_label')}
        hint=${t('settings_app.chat_directory_hint')}
        roots=${roots} dirs=${dirs}
        mode="single" requireWritable=${true}
        value=${directory} disabled=${busy || noWritable}
        onChange=${setDirectory} />

      <button class="app-save" disabled=${busy || !dirty}
        onClick=${() => run(() => transport.setChatDirectory(directory, signFn))}>
        ${busy ? t('settings_app.saving') : t('settings_app.save')}
      </button>

      <div class="settings-row" style="margin-top:12px">
        <${ToggleSwitch} checked=${linkPreview} disabled=${busy}
          onChange=${(v) => {
            setLinkPreview(v);
            run(() => transport.setChatLinkPreview(v, signFn));
          }}
          label=${t('settings_app.chat_link_preview_label')} />
        <p class="settings-hint">${t('settings_app.chat_link_preview_hint')}</p>
      </div>
      ${msg && html`<p class="settings-hint">${msg}</p>`}
    </div>
  `;
}

export { ChatSettings };