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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
import {
html, useState, useEffect, useCallback,
} from './vendor/htm-preact.js';
import { t } from './i18n.js';
import { hubFetch, navigate } from './hub-client.js';
import * as platform from './platform.js';
import { GroupName } from './group-name.js';
import { Icon } from './icon.js';
export function ExplorePage({ token, myGroupIds, allowPublicGroups = true }) {
const [groups, setGroups] = useState([]);
const [loading, setLoading] = useState(true);
const [search, setSearch] = useState('');
const [joining, setJoining] = useState(null);
const doSearch = useCallback((q) => {
setLoading(true);
const url = q ? `/v1/groups?q=${encodeURIComponent(q)}` : '/v1/groups';
hubFetch(url, { token })
.then(data => setGroups(data.groups || []))
.catch(() => {})
.finally(() => setLoading(false));
}, [token]);
useEffect(() => { doSearch(''); }, [token]);
const onSearch = useCallback((e) => {
const q = e.target.value;
setSearch(q);
doSearch(q);
}, [doSearch]);
const joinGroup = useCallback(async (gid) => {
setJoining(gid);
try {
await hubFetch(`/v1/groups/${gid}/join`, { method: 'POST', token });
navigate(`/group/${gid}`);
setTimeout(() => window.location.reload(), 100);
} catch (err) {
if (err.message.includes('Already a member')) {
navigate(`/group/${gid}`);
} else {
alert(err.message);
}
} finally {
setJoining(null);
}
}, [token]);
const isMember = (gid) => myGroupIds && myGroupIds.includes(gid);
if (!allowPublicGroups) {
return html`<div><p class="page-message">${t('explore.disabled')}</p></div>`;
}
return html`
<div>
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px">
<h2 style="margin:0">${t('explore.title')}</h2>
${platform.node.available && html`
<a class="admin-btn" href="#/create-group">${t('explore.create_group')}</a>
`}
</div>
<div class="file-toolbar" style="margin-bottom:16px">
<input type="text" class="admin-search" placeholder="${t('explore.search')}"
value=${search} onInput=${onSearch} />
</div>
${loading
? html`<p class="page-message">${t('explore.loading')}</p>`
: groups.length === 0
? html`<p class="page-message">${t('explore.empty')}</p>`
: html`
<div class="group-grid">
${groups.map(g => html`
<div key=${g.id} class="group-card">
<a href="#/group/${g.id}" style="text-decoration:none;color:inherit">
<h3><${GroupName} name=${g.name}
owner=${g.source && g.source !== 'local' ? g.source : g.owner_username} /></h3>
${g.description && html`<p class="group-card-desc">${g.description}</p>`}
</a>
<span class="badge">${g.join_policy}</span>
${' '}
${isMember(g.id)
? html`<span class="badge">${t('explore.member')}</span>`
: g.join_policy === 'open' && html`
<button class="admin-btn" style="margin-top:8px"
disabled=${joining === g.id}
onClick=${() => joinGroup(g.id)}>
${joining === g.id ? '...' : t('explore.join')}
</button>
`
}
</div>
`)}
</div>
`
}
</div>
`;
}
|