🆕 Groups Forum

- please add the text in the UITexts
This commit is contained in:
DuckieTM
2026-03-29 14:58:56 +02:00
parent 5d8c5d3eea
commit 522219cbee
7 changed files with 90 additions and 11 deletions
+15 -1
View File
@@ -38,5 +38,19 @@
"wiredfurni.params.texts.placeholder_type": "Tipo di segnaposto:",
"wiredfurni.params.texts.placeholder_type.1": "Singolo",
"wiredfurni.params.texts.placeholder_type.2": "Multiplo",
"wiredfurni.params.texts.select_delimiter": "Seleziona il delimitatore:"
"wiredfurni.params.texts.select_delimiter": "Seleziona il delimitatore:",
"groupforum.list.tab.most_active": "Meest active threads",
"groupforum.list.tab.my_forums": "Mijn group forums",
"groupforum.list.no_forums": "Er zijn geen forums",
"groupforum.view.threads": "Aantal threads",
"groupforum.thread.pin": "Pin hem vast",
"groupforum.thread.unpin": "Unpin bericht",
"groupforum.thread.lock": "Lock de thread",
"groupforum.thread.unlock": "Unlock de thread",
"groupforum.thread.hide": "Verberg thread",
"groupforum.thread.restore": "Maak thread weer zichtbaar",
"groupforum.thread.delete": "Verwijder thread + posts",
"groupforum.message.hide": "Verberg bericht",
"group.forum.enable.caption": "Enable / Disable Group forum",
"group.forum.enable.help": "Als je de group forum disabled dan verwijderen ook alle posts!"
}
+1
View File
@@ -8,6 +8,7 @@ export interface IGroupData
groupHomeroomId: number;
groupState: number;
groupCanMembersDecorate: boolean;
groupHasForum: boolean;
groupColors: number[];
groupBadgeParts: GroupBadgePart[];
}
@@ -77,6 +77,7 @@ export const GroupManagerView: FC<{}> = props =>
groupHomeroomId: parser.roomId,
groupState: parser.state,
groupCanMembersDecorate: parser.canMembersDecorate,
groupHasForum: parser.hasForum,
groupColors: [ parser.colorA, parser.colorB ],
groupBadgeParts
});
@@ -85,7 +86,7 @@ export const GroupManagerView: FC<{}> = props =>
if(!groupData || (groupData.groupId <= 0)) return null;
return (
<NitroCardView className="nitro-group-manager">
<NitroCardView className="nitro-group-manager w-[555px] h-[415px]">
<NitroCardHeaderView headerText={ LocalizeText('group.window.title') } onCloseClick={ onClose } />
<NitroCardTabsView>
{ TABS.map(tab =>
@@ -16,7 +16,7 @@ export const GroupForumListView: FC<GroupForumListViewProps> = props =>
{
const { onOpenForum = null } = props;
const [ forums, setForums ] = useState<ForumData[]>([]);
const [ listMode, setListMode ] = useState<number>(2); // 2 = most active
const [ listMode, setListMode ] = useState<number>(0); // 0 = most active
const [ startIndex, setStartIndex ] = useState<number>(0);
const [ totalForums, setTotalForums ] = useState<number>(0);
@@ -59,8 +59,8 @@ export const GroupForumListView: FC<GroupForumListViewProps> = props =>
className="form-select form-select-sm"
value={ listMode }
onChange={ e => { setListMode(parseInt(e.target.value)); setStartIndex(0); } }>
<option value={ 2 }>{ LocalizeText('groupforum.list.tab.most_active') }</option>
<option value={ 1 }>{ LocalizeText('groupforum.list.tab.my_forums') }</option>
<option value={ 0 }>{ LocalizeText('groupforum.list.tab.most_active') }</option>
<option value={ 2 }>{ LocalizeText('groupforum.list.tab.my_forums') }</option>
</select>
</Flex>
</Flex>
@@ -101,7 +101,7 @@ export const GroupForumThreadListView: FC<GroupForumThreadListViewProps> = props
<Button variant="link" className="btn-sm" onClick={ onOpenSettings }>
{ LocalizeText('groupforum.view.settings.header') }
</Button> }
{ forumData && forumData.hasPostThreadPermissionError &&
{ forumData && forumData.hasReadPermissionError && forumData.hasPostThreadPermissionError &&
<Button variant="primary" className="btn-sm" onClick={ onNewThread }>
{ LocalizeText('messageboard.new.thread.button') }
</Button> }
@@ -119,6 +119,16 @@ export const GroupForumThreadListView: FC<GroupForumThreadListViewProps> = props
<Text small>{ forumData.totalMessages } { LocalizeText('messageboard.messages') }</Text>
</Column>
</Flex> }
{ forumData && !forumData.hasReadPermissionError &&
<Flex className="flex-1 p-4" justifyContent="center" alignItems="center">
<Column alignItems="center" gap={ 2 }>
<Text bold>{ LocalizeText('groupforum.view.error.operation_read') }</Text>
<Text small variant="muted">
{ LocalizeText('groupforum.view.error.' + forumData.readPermissionError) }
</Text>
</Column>
</Flex> }
{ (!forumData || forumData.hasReadPermissionError) &&
<Column className="overflow-auto flex-1" gap={ 0 }>
{ sortedThreads.map((thread, index) =>
{
@@ -195,7 +205,7 @@ export const GroupForumThreadListView: FC<GroupForumThreadListViewProps> = props
{ LocalizeText('groupforum.list.load_more') }
</Text>
</Flex> }
</Column>
</Column> }
</Column>
);
};
@@ -1,4 +1,4 @@
import { GetMessagesMessageComposer, ModerateMessageMessageComposer, ModerateThreadMessageComposer, PostMessageMessageComposer, PostMessageMessageEvent, PostThreadMessageEvent, ThreadMessagesMessageEvent, UpdateMessageMessageEvent, UpdateThreadMessageComposer, UpdateThreadMessageEvent } from '@nitrots/nitro-renderer';
import { GetMessagesMessageComposer, ModerateMessageMessageComposer, ModerateThreadMessageComposer, PostMessageMessageComposer, PostMessageMessageEvent, PostThreadMessageEvent, ThreadMessagesMessageEvent, UpdateForumReadMarkerMessageComposer, UpdateForumReadMarkerEntry, UpdateMessageMessageEvent, UpdateThreadMessageComposer, UpdateThreadMessageEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { LocalizeText, SendMessageComposer, GetUserProfile } from '../../../../api';
import { Button, Column, Flex, LayoutAvatarImageView, Text } from '../../../../common';
@@ -49,6 +49,15 @@ export const GroupForumThreadView: FC<GroupForumThreadViewProps> = props =>
{
setMessages(prev => [ ...prev, ...parser.messages ]);
}
// Mark messages as read
if(parser.messages.length > 0)
{
const lastMessage = parser.messages[parser.messages.length - 1];
SendMessageComposer(new UpdateForumReadMarkerMessageComposer(
new UpdateForumReadMarkerEntry(effectiveGroupId, lastMessage.messageId, true)
));
}
});
useMessageEvent<PostMessageMessageEvent>(PostMessageMessageEvent, event =>
@@ -153,6 +162,12 @@ export const GroupForumThreadView: FC<GroupForumThreadViewProps> = props =>
onBack();
}, [ effectiveGroupId, threadId, onBack ]);
const deleteThread = useCallback(() =>
{
SendMessageComposer(new ModerateThreadMessageComposer(effectiveGroupId, threadId, STATE_DELETED_BY_MODERATOR));
onBack();
}, [ effectiveGroupId, threadId, onBack ]);
const formatTimeAgo = (seconds: number): string =>
{
if(seconds < 60) return `${ seconds }s ${ LocalizeText('messageboard.time.ago') }`;
@@ -203,6 +218,9 @@ export const GroupForumThreadView: FC<GroupForumThreadViewProps> = props =>
<Button variant="outline-danger" className="btn-sm" onClick={ hideThread }>
{ LocalizeText('groupforum.thread.hide') }
</Button>
<Button variant="danger" className="btn-sm" onClick={ deleteThread }>
{ LocalizeText('groupforum.thread.delete') }
</Button>
</Flex> }
</Flex>
<Column className="overflow-auto flex-1" gap={ 0 }>
@@ -292,6 +310,12 @@ export const GroupForumThreadView: FC<GroupForumThreadViewProps> = props =>
<Flex className="p-2 border-t bg-warning bg-opacity-10" justifyContent="center">
<Text small variant="muted">{ LocalizeText('groupforum.thread.locked') }</Text>
</Flex> }
{ !canPost && !isLocked && forumData &&
<Flex className="p-2 border-t bg-muted" justifyContent="center">
<Text small variant="muted">
{ LocalizeText('groupforum.view.error.' + forumData.postMessagePermissionError) }
</Text>
</Flex> }
</Column>
);
};
@@ -2,6 +2,7 @@ import { GroupSavePreferencesComposer } from '@nitrots/nitro-renderer';
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from 'react';
import { IGroupData, LocalizeText, SendMessageComposer } from '../../../../api';
import { Flex, HorizontalRule, Text } from '../../../../common';
import { useNotification } from '../../../../hooks';
const STATES: string[] = [ 'regular', 'exclusive', 'private' ];
@@ -17,12 +18,30 @@ export const GroupTabSettingsView: FC<GroupTabSettingsViewProps> = props =>
const { groupData = null, setGroupData = null, setCloseAction = null } = props;
const [ groupState, setGroupState ] = useState<number>(groupData.groupState);
const [ groupDecorate, setGroupDecorate ] = useState<boolean>(groupData.groupCanMembersDecorate);
const [ groupForum, setGroupForum ] = useState<boolean>(groupData.groupHasForum ?? false);
const { showConfirm = null } = useNotification();
const handleForumToggle = useCallback(() =>
{
if(groupForum)
{
// Disabling forum - show confirmation
showConfirm(LocalizeText('group.forum.disable.confirm'), () =>
{
setGroupForum(false);
}, null);
}
else
{
setGroupForum(true);
}
}, [ groupForum, showConfirm ]);
const saveSettings = useCallback(() =>
{
if(!groupData) return false;
if((groupState === groupData.groupState) && (groupDecorate === groupData.groupCanMembersDecorate)) return true;
if((groupState === groupData.groupState) && (groupDecorate === groupData.groupCanMembersDecorate) && (groupForum === (groupData.groupHasForum ?? false))) return true;
if(groupData.groupId <= 0)
{
@@ -32,6 +51,7 @@ export const GroupTabSettingsView: FC<GroupTabSettingsViewProps> = props =>
newValue.groupState = groupState;
newValue.groupCanMembersDecorate = groupDecorate;
newValue.groupHasForum = groupForum;
return newValue;
});
@@ -39,15 +59,16 @@ export const GroupTabSettingsView: FC<GroupTabSettingsViewProps> = props =>
return true;
}
SendMessageComposer(new GroupSavePreferencesComposer(groupData.groupId, groupState, groupDecorate ? 0 : 1));
SendMessageComposer(new GroupSavePreferencesComposer(groupData.groupId, groupState, groupDecorate ? 0 : 1, groupForum));
return true;
}, [ groupData, groupState, groupDecorate, setGroupData ]);
}, [ groupData, groupState, groupDecorate, groupForum, setGroupData ]);
useEffect(() =>
{
setGroupState(groupData.groupState);
setGroupDecorate(groupData.groupCanMembersDecorate);
setGroupForum(groupData.groupHasForum ?? false);
}, [ groupData ]);
useEffect(() =>
@@ -84,6 +105,14 @@ export const GroupTabSettingsView: FC<GroupTabSettingsViewProps> = props =>
<Text>{ LocalizeText('group.edit.settings.rights.members.help') }</Text>
</div>
</div>
<HorizontalRule />
<div className="flex items-center gap-1">
<input checked={ groupForum } className="form-check-input" type="checkbox" onChange={ handleForumToggle } />
<div className="flex flex-col gap-1">
<Text bold>{ LocalizeText('group.forum.enable.caption') }</Text>
<Text>{ LocalizeText('group.forum.enable.help') }</Text>
</div>
</div>
</div>
);
};