hint messages update

This commit is contained in:
2026-04-02 18:15:10 -04:00
parent e4ac7e248c
commit ae47f66ef5
5 changed files with 22 additions and 16 deletions

View File

@@ -80,18 +80,18 @@ router.get('/search', authMiddleware, async (req, res) => {
const group = await queryOne(req.schema, 'SELECT type, is_direct FROM groups WHERE id = $1', [parseInt(groupId)]);
if (group && (group.type === 'private' || group.is_direct)) {
users = await query(req.schema,
`SELECT u.id,u.name,u.display_name,u.avatar,u.role,u.status,u.hide_admin_tag,u.allow_dm,u.is_minor FROM users u JOIN group_members gm ON gm.user_id=u.id AND gm.group_id=$1 WHERE u.status='active' AND u.id!=$2 AND (u.name ILIKE $3 OR u.display_name ILIKE $3) ORDER BY u.name ASC${isTyped ? ' LIMIT 10' : ''}`,
`SELECT u.id,u.name,u.display_name,u.avatar,u.role,u.status,u.hide_admin_tag,u.allow_dm,u.is_minor,u.is_default_admin FROM users u JOIN group_members gm ON gm.user_id=u.id AND gm.group_id=$1 WHERE u.status='active' AND u.id!=$2 AND (u.name ILIKE $3 OR u.display_name ILIKE $3) ORDER BY u.name ASC${isTyped ? ' LIMIT 10' : ''}`,
[parseInt(groupId), req.user.id, `%${q}%`]
);
} else {
users = await query(req.schema,
`SELECT id,name,display_name,avatar,role,status,hide_admin_tag,allow_dm,is_minor FROM users WHERE status='active' AND id!=$1 AND (name ILIKE $2 OR display_name ILIKE $2) ORDER BY name ASC${isTyped ? ' LIMIT 10' : ''}`,
`SELECT id,name,display_name,avatar,role,status,hide_admin_tag,allow_dm,is_minor,is_default_admin FROM users WHERE status='active' AND id!=$1 AND (name ILIKE $2 OR display_name ILIKE $2) ORDER BY name ASC${isTyped ? ' LIMIT 10' : ''}`,
[req.user.id, `%${q}%`]
);
}
} else {
users = await query(req.schema,
`SELECT id,name,display_name,avatar,role,status,hide_admin_tag,allow_dm,is_minor FROM users WHERE status='active' AND (name ILIKE $1 OR display_name ILIKE $1) ORDER BY name ASC${isTyped ? ' LIMIT 10' : ''}`,
`SELECT id,name,display_name,avatar,role,status,hide_admin_tag,allow_dm,is_minor,is_default_admin FROM users WHERE status='active' AND (name ILIKE $1 OR display_name ILIKE $1) ORDER BY name ASC${isTyped ? ' LIMIT 10' : ''}`,
[`%${q}%`]
);
}

View File

@@ -40,7 +40,7 @@ export default function AddChildAliasModal({ features = {}, onClose }) {
setPartner(p);
setSelectedPartnerId(p?.id?.toString() || '');
setRespondSeparately(p?.respond_separately || false);
setAllUsers((usersRes.users || []).filter(u => u.id !== currentUser?.id));
setAllUsers((usersRes.users || []).filter(u => u.id !== currentUser?.id && !u.is_default_admin));
if (isMixedAge) {
setMinorPlayers(thirdRes.users || []);
} else {

View File

@@ -69,7 +69,7 @@ function MessagesTab() {
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: 'msgGroup', label: 'User 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.' },
];
@@ -162,18 +162,18 @@ function TeamManagementTab() {
const LOGIN_TYPE_OPTIONS = [
{
id: 'all_ages',
label: 'Unrestricted',
desc: 'No age restrictions. All users interact normally. Default behaviour.',
label: 'Unrestricted (default)',
desc: 'No age restrictions. All users interact normally.',
},
{
id: 'guardian_only',
label: 'Guardian Only',
desc: "Parents are required to add their child's details in their profile. They respond on behalf of the child for events with availability tracking for the players group.",
desc: "Parents/Guardians login one. Parents/Guardians are required to add their child's details in the \"Family Manager\". They will also respond on behalf of the child for events with availability tracking.",
},
{
id: 'mixed_age',
label: 'Restricted',
desc: "Parents, or user managers, add the minor's user account to their guardian profile. Minor aged users cannot login until a manager approves the guardian link.",
desc: "No age restriction for login. Date of Birth is a required field. Parents/Guardians must select their child in the Family Manager to allow them to login. Any private message initiated by any adult to a minor aged user will include the child's designated guardian.",
},
];
@@ -247,7 +247,7 @@ function LoginTypeTab() {
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, marginBottom: 16 }}>
<div>
<label className="text-sm font-medium" style={{ color: 'var(--text-secondary)', display: 'block', marginBottom: 4 }}>Players Group</label>
<p style={{ fontSize: 12, color: 'var(--text-tertiary)', marginBottom: 6 }}>The user group that children / aliases are added to.</p>
<p style={{ fontSize: 12, color: 'var(--text-tertiary)', marginBottom: 6 }}>Select a group that minor aged users will be put in by default. *</p>
<select className="input" value={playersGroupId} disabled={!canChange}
onChange={e => setPlayersGroupId(e.target.value)}>
<option value=""> Select group </option>
@@ -256,13 +256,16 @@ function LoginTypeTab() {
</div>
<div>
<label className="text-sm font-medium" style={{ color: 'var(--text-secondary)', display: 'block', marginBottom: 4 }}>Guardians Group</label>
<p style={{ fontSize: 12, color: 'var(--text-tertiary)', marginBottom: 6 }}>Members of this group see the "Add Child" option in their profile.</p>
<p style={{ fontSize: 12, color: 'var(--text-tertiary)', marginBottom: 6 }}>Members of the selected group will have access to Family Manager. *</p>
<select className="input" value={guardiansGroupId} disabled={!canChange}
onChange={e => setGuardiansGroupId(e.target.value)}>
<option value=""> Select group </option>
{userGroups.map(g => <option key={g.id} value={g.id}>{g.name}</option>)}
</select>
</div>
<p style={{ fontSize: 12, color: 'var(--text-tertiary)', marginTop: 4 }}>
* Open Group Manager to create a different group, if none are suitable in these lists.
</p>
</div>
)}
@@ -396,7 +399,7 @@ function RegistrationTab({ onFeaturesChanged }) {
// ── Main modal ────────────────────────────────────────────────────────────────
export default function SettingsModal({ onClose, onFeaturesChanged }) {
const [tab, setTab] = useState('messages');
const [tab, setTab] = useState('login-type');
const [appType, setAppType] = useState('RosterChirp-Chat');
useEffect(() => {
@@ -424,9 +427,9 @@ export default function SettingsModal({ onClose, onFeaturesChanged }) {
<div style={{ marginBottom: 24 }}>
<label className="text-sm" style={{ color: 'var(--text-tertiary)', display: 'block', marginBottom: 4 }}>SELECT OPTION:</label>
<select className="input" value={tab} onChange={e => setTab(e.target.value)}>
<option value="login-type">Login Type</option>
<option value="messages">Messages</option>
{isTeam && <option value="team">Tools</option>}
<option value="login-type">Login Type</option>
<option value="registration">Registration</option>
</select>
</div>

View File

@@ -137,15 +137,18 @@ export default function Chat() {
}).catch(() => {});
}, [features.loginType, features.inGuardiansGroup]);
// Close help — open deferred add-child popup if pending
// Close help — open deferred add-child popup if pending, or settings for first-time default admin
const handleHelpClose = useCallback(() => {
if (addChildPending) {
setAddChildPending(false);
setModal('addchild');
} else if (!helpDismissed && user?.is_default_admin && !localStorage.getItem('rosterchirp_admin_setup_shown')) {
localStorage.setItem('rosterchirp_admin_setup_shown', '1');
setModal('settings');
} else {
setModal(null);
}
}, [addChildPending]);
}, [addChildPending, helpDismissed, user]);
// Register / refresh push subscription — FCM for Android/Chrome, Web Push for iOS
useEffect(() => {

View File

@@ -759,7 +759,7 @@ export default function GroupManagerPage({ isMobile = false, onProfile, onHelp,
const onRefresh = () => setRefreshKey(k => k+1);
useEffect(() => {
api.searchUsers('').then(({ users }) => setAllUsers(users.filter(u => u.status==='active').sort((a, b) => (a.display_name||a.name).localeCompare(b.display_name||b.name)))).catch(() => {});
api.searchUsers('').then(({ users }) => setAllUsers(users.filter(u => u.status==='active' && !u.is_default_admin).sort((a, b) => (a.display_name||a.name).localeCompare(b.display_name||b.name)))).catch(() => {});
api.getUserGroups().then(({ groups }) => setAllUserGroups([...(groups||[])].sort((a, b) => a.name.localeCompare(b.name)))).catch(() => {});
api.getSettings().then(({ settings }) => {
const pgid = (settings || []).find(s => s.key === 'feature_players_group_id')?.value;