v0.12.41 New settings options for messages

This commit is contained in:
2026-03-30 08:04:36 -04:00
parent ff6743c9b1
commit 6a2f4438f9
11 changed files with 154 additions and 24 deletions

View File

@@ -10,6 +10,94 @@ const APP_TYPES = {
'RosterChirp-Team': { label: 'RosterChirp-Team', desc: 'Chat, Branding, Group Manager and Schedule Manager.' },
};
// ── Toggle switch ─────────────────────────────────────────────────────────────
function Toggle({ checked, onChange }) {
return (
<div
onClick={() => onChange(!checked)}
role="switch"
aria-checked={checked}
style={{
width: 44, height: 24, borderRadius: 12, cursor: 'pointer', flexShrink: 0,
background: checked ? 'var(--primary)' : 'var(--border)',
position: 'relative', transition: 'background 0.2s',
}}
>
<div style={{
position: 'absolute', top: 2, left: checked ? 22 : 2,
width: 20, height: 20, borderRadius: '50%',
background: 'white', transition: 'left 0.2s',
boxShadow: '0 1px 3px rgba(0,0,0,0.3)',
}} />
</div>
);
}
// ── Messages Tab ──────────────────────────────────────────────────────────────
function MessagesTab() {
const toast = useToast();
const [settings, setSettings] = useState({
msgPublic: true,
msgGroup: true,
msgPrivateGroup: true,
msgU2U: true,
});
const [saving, setSaving] = useState(false);
useEffect(() => {
api.getSettings().then(({ settings: s }) => {
setSettings({
msgPublic: s.feature_msg_public !== 'false',
msgGroup: s.feature_msg_group !== 'false',
msgPrivateGroup: s.feature_msg_private_group !== 'false',
msgU2U: s.feature_msg_u2u !== 'false',
});
}).catch(() => {});
}, []);
const toggle = (key) => setSettings(prev => ({ ...prev, [key]: !prev[key] }));
const handleSave = async () => {
setSaving(true);
try {
await api.updateMessageSettings(settings);
toast('Message settings saved', 'success');
window.dispatchEvent(new Event('rosterchirp:settings-changed'));
} catch (e) { toast(e.message, 'error'); }
finally { setSaving(false); }
};
const rows = [
{ key: 'msgPublic', label: 'Public Messages', desc: 'Public group channels visible to all members.' },
{ key: 'msgGroup', label: 'Group Messages', desc: 'Private group messages managed by User Groups.' },
{ key: 'msgPrivateGroup', label: 'Private Group Messages', desc: 'Private multi-member group conversations.' },
{ key: 'msgU2U', label: 'Private Messages (U2U)', desc: 'One-on-one direct messages between users.' },
];
return (
<div>
<div className="settings-section-label">Message Features</div>
<p style={{ fontSize: 12, color: 'var(--text-tertiary)', marginBottom: 16 }}>
Disable a feature to hide it from all menus, sidebars, and modals.
</p>
<div style={{ border: '1px solid var(--border)', borderRadius: 'var(--radius)', overflow: 'hidden', marginBottom: 16 }}>
{rows.map((r, i) => (
<div key={r.key} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '12px 14px', borderBottom: i < rows.length - 1 ? '1px solid var(--border)' : 'none' }}>
<div style={{ flex: 1 }}>
<div style={{ fontSize: 14, fontWeight: 500 }}>{r.label}</div>
<div style={{ fontSize: 12, color: 'var(--text-tertiary)', marginTop: 2 }}>{r.desc}</div>
</div>
<Toggle checked={settings[r.key]} onChange={() => toggle(r.key)} />
</div>
))}
</div>
<button className="btn btn-primary" onClick={handleSave} disabled={saving}>
{saving ? 'Saving…' : 'Save'}
</button>
</div>
);
}
// ── Team Management Tab ───────────────────────────────────────────────────────
function TeamManagementTab() {
const toast = useToast();
@@ -193,7 +281,7 @@ function RegistrationTab({ onFeaturesChanged }) {
// ── Main modal ────────────────────────────────────────────────────────────────
export default function SettingsModal({ onClose, onFeaturesChanged }) {
const [tab, setTab] = useState('registration');
const [tab, setTab] = useState('messages');
const [appType, setAppType] = useState('RosterChirp-Chat');
useEffect(() => {
@@ -208,7 +296,8 @@ export default function SettingsModal({ onClose, onFeaturesChanged }) {
const isTeam = appType === 'RosterChirp-Team';
const tabs = [
isTeam && { id: 'team', label: 'Team Management' },
{ id: 'messages', label: 'Messages' },
isTeam && { id: 'team', label: 'Tools' },
{ id: 'registration', label: 'Registration' },
].filter(Boolean);
@@ -231,6 +320,7 @@ export default function SettingsModal({ onClose, onFeaturesChanged }) {
))}
</div>
{tab === 'messages' && <MessagesTab />}
{tab === 'team' && <TeamManagementTab />}
{tab === 'registration' && <RegistrationTab onFeaturesChanged={onFeaturesChanged} />}
</div>