Localize all hardcoded texts in mod tools using LocalizeText

Replace ~70 hardcoded English strings across 15 mod-tools files
with LocalizeText() calls using moderation.* keys matching the
existing ExternalTexts convention. Includes mod-tools-external-texts.json
with all required keys for ExternalTexts.json.
This commit is contained in:
simoleo89
2026-03-18 20:42:53 +01:00
parent bffaccf6a3
commit 349498ec34
16 changed files with 222 additions and 124 deletions
+96
View File
@@ -0,0 +1,96 @@
{
"moderation.modtools.title": "Mod Tools",
"moderation.modtools.roomtool": "Room Tool",
"moderation.modtools.roomchatlogs": "Chatlog Tool",
"moderation.modtools.userinfo": "User Info",
"moderation.modtools.tickets": "Tickets",
"moderation.roomtool.info.title": "Room Info",
"moderation.roomtool.roomowner.title": "Owner:",
"moderation.roomtool.usersinroom.title": "Users in room:",
"moderation.roomtool.ownerinroom.title": "Owner here:",
"moderation.roomtool.true.title": "Yes",
"moderation.roomtool.false.title": "No",
"moderation.roomtool.button.visit.title": "Visit Room",
"moderation.roomtool.kickall.title": "Kick everyone out",
"moderation.roomtool.closeroom.title": "Enable the doorbell",
"moderation.roomtool.inappropiatename.title": "Change room name",
"moderation.roomtool.presets.title": "Type a mandatory message...",
"moderation.roomtool.button.caution.title": "Send Caution",
"moderation.roomtool.button.message.title": "Send Alert",
"moderation.tickets.title": "Tickets",
"moderation.tickets.open": "Open Issues",
"moderation.tickets.my": "My Issues",
"moderation.tickets.picked": "Picked Issues",
"moderation.tickets.col.type": "Type",
"moderation.tickets.col.roomPlayer": "Room/Player",
"moderation.tickets.col.opened": "Opened",
"moderation.tickets.col.picker": "Picker",
"moderation.tickets.pick": "Pick Issue",
"moderation.tickets.handle": "Handle",
"moderation.tickets.release": "Release",
"moderation.issue.resolving": "Resolving issue %id%",
"moderation.issue.info": "Issue Information",
"moderation.issue.source": "Source",
"moderation.issue.category": "Category",
"moderation.issue.description": "Description",
"moderation.issue.caller": "Caller",
"moderation.issue.reported": "Reported User",
"moderation.issue.chatlog": "Chatlog",
"moderation.issue.close.useless": "Close as useless",
"moderation.issue.close.abusive": "Close as abusive",
"moderation.issue.close.resolved": "Close as resolved",
"moderation.issue.release": "Release",
"moderation.chatlog.issue": "Issue Chatlog",
"moderation.chatlog.room": "Room Chatlog",
"moderation.chatlog.col.time": "Time",
"moderation.chatlog.col.user": "User",
"moderation.chatlog.col.message": "Message",
"moderation.chatlog.visit": "Visit",
"moderation.chatlog.roomtools": "Room Tools",
"moderation.chatlog.user": "User Chatlog: %username%",
"moderation.userinfo.roomchat": "Room Chat",
"moderation.userinfo.sendmessage": "Send Message",
"moderation.userinfo.roomvisits": "Room Visits",
"moderation.userinfo.modaction": "Mod Action",
"moderation.sendmessage.title": "Send Message",
"moderation.sendmessage.to": "Message To: %username%",
"moderation.sendmessage.send": "Send message",
"moderation.sendmessage.error.empty": "Please write a message to user.",
"moderation.error": "Error",
"moderation.roomvisits.title": "User Visits",
"moderation.roomvisits.col.time": "Time",
"moderation.roomvisits.col.roomname": "Room name",
"moderation.roomvisits.col.visit": "Visit",
"moderation.roomvisits.visitroom": "Visit Room",
"moderation.modaction.title": "Mod Action: %username%",
"moderation.modaction.cfhtopic": "CFH Topic",
"moderation.modaction.sanctiontype": "Sanction Type",
"moderation.modaction.message.hint": "Optional message type, overrides default",
"moderation.modaction.defaultsanction": "Default Sanction",
"moderation.modaction.sanction": "Sanction",
"moderation.modaction.alert": "Alert",
"moderation.modaction.mute1h": "Mute 1h",
"moderation.modaction.ban18h": "Ban 18h",
"moderation.modaction.ban7days": "Ban 7 days",
"moderation.modaction.ban30days.step1": "Ban 30 days (step 1)",
"moderation.modaction.ban30days.step2": "Ban 30 days (step 2)",
"moderation.modaction.ban100years": "Ban 100 years",
"moderation.modaction.banavataronly100years": "Ban avatar-only 100 years",
"moderation.modaction.kick": "Kick",
"moderation.modaction.locktrade1week": "Lock trade 1 week",
"moderation.modaction.locktradepermanent": "Lock trade permanent",
"moderation.modaction.message": "Message",
"moderation.modaction.error.notopic": "You must select a CFH topic",
"moderation.modaction.error.notopicorsanction": "You must select a CFH topic and Sanction",
"moderation.modaction.error.nopermission": "You do not have permission to do this",
"moderation.modaction.error.nosanction": "You must select a sanction",
"moderation.modaction.error.emptymessage": "Please write a message to user"
}
+6 -6
View File
@@ -1,6 +1,6 @@
import { AddLinkEventTracker, CreateLinkEvent, ILinkEventTracker, RemoveLinkEventTracker, RoomEngineEvent, RoomId, RoomObjectCategory, RoomObjectType } from '@nitrots/nitro-renderer'; import { AddLinkEventTracker, CreateLinkEvent, ILinkEventTracker, RemoveLinkEventTracker, RoomEngineEvent, RoomId, RoomObjectCategory, RoomObjectType } from '@nitrots/nitro-renderer';
import { FC, useEffect, useRef, useState } from 'react'; import { FC, useEffect, useRef, useState } from 'react';
import { GetRoomSession, ISelectedUser } from '../../api'; import { GetRoomSession, ISelectedUser, LocalizeText } from '../../api';
import { Button, DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common'; import { Button, DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common';
import { useModTools, useNitroEvent, useObjectSelectedEvent } from '../../hooks'; import { useModTools, useNitroEvent, useObjectSelectedEvent } from '../../hooks';
import { ModToolsChatlogView } from './views/room/ModToolsChatlogView'; import { ModToolsChatlogView } from './views/room/ModToolsChatlogView';
@@ -125,23 +125,23 @@ export const ModToolsView: FC<{}> = props =>
<> <>
{ isVisible && { isVisible &&
<NitroCardView className="nitro-mod-tools min-w-[200px]" theme="primary-slim" uniqueKey="mod-tools" windowPosition={ DraggableWindowPosition.TOP_LEFT } > <NitroCardView className="nitro-mod-tools min-w-[200px]" theme="primary-slim" uniqueKey="mod-tools" windowPosition={ DraggableWindowPosition.TOP_LEFT } >
<NitroCardHeaderView headerText={ 'Mod Tools' } onCloseClick={ event => setIsVisible(false) } /> <NitroCardHeaderView headerText={ LocalizeText('moderation.modtools.title') } onCloseClick={ event => setIsVisible(false) } />
<NitroCardContentView className="text-black" gap={ 2 }> <NitroCardContentView className="text-black" gap={ 2 }>
<Button active={ isRoomInfoOpen } disabled={ (currentRoomId <= 0) } gap={ 2 } justifyContent="start" onClick={ event => CreateLinkEvent(`mod-tools/toggle-room-info/${ currentRoomId }`) }> <Button active={ isRoomInfoOpen } disabled={ (currentRoomId <= 0) } gap={ 2 } justifyContent="start" onClick={ event => CreateLinkEvent(`mod-tools/toggle-room-info/${ currentRoomId }`) }>
<div className="nitro-icon icon-small-room shrink-0" /> Room Tool <div className="nitro-icon icon-small-room shrink-0" /> { LocalizeText('moderation.modtools.roomtool') }
</Button> </Button>
<Button active={ isRoomChatlogOpen } disabled={ (currentRoomId <= 0) } gap={ 2 } innerRef={ elementRef } justifyContent="start" onClick={ event => CreateLinkEvent(`mod-tools/toggle-room-chatlog/${ currentRoomId }`) }> <Button active={ isRoomChatlogOpen } disabled={ (currentRoomId <= 0) } gap={ 2 } innerRef={ elementRef } justifyContent="start" onClick={ event => CreateLinkEvent(`mod-tools/toggle-room-chatlog/${ currentRoomId }`) }>
<div className="nitro-icon icon-chat-history shrink-0" /> Chatlog Tool <div className="nitro-icon icon-chat-history shrink-0" /> { LocalizeText('moderation.modtools.roomchatlogs') }
</Button> </Button>
<Button active={ !!isUserInfoOpen } disabled={ !selectedUser } gap={ 2 } justifyContent="start" onClick={ () => CreateLinkEvent(`mod-tools/toggle-user-info/${ selectedUser.userId }`) }> <Button active={ !!isUserInfoOpen } disabled={ !selectedUser } gap={ 2 } justifyContent="start" onClick={ () => CreateLinkEvent(`mod-tools/toggle-user-info/${ selectedUser.userId }`) }>
<div className="nitro-icon icon-user shrink-0" /> <div className="nitro-icon icon-user shrink-0" />
{ selectedUser { selectedUser
? <span className="truncate">{ selectedUser.username }</span> ? <span className="truncate">{ selectedUser.username }</span>
: <span className="opacity-50 italic">Select a user</span> : <span className="opacity-50 italic">{ LocalizeText('moderation.modtools.userinfo') }</span>
} }
</Button> </Button>
<Button active={ isTicketsVisible } gap={ 2 } justifyContent="start" onClick={ () => setIsTicketsVisible(prevValue => !prevValue) }> <Button active={ isTicketsVisible } gap={ 2 } justifyContent="start" onClick={ () => setIsTicketsVisible(prevValue => !prevValue) }>
<div className="nitro-icon icon-tickets shrink-0" /> Report Tool <div className="nitro-icon icon-tickets shrink-0" /> { LocalizeText('moderation.modtools.tickets') }
</Button> </Button>
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> } </NitroCardView> }
@@ -1,6 +1,6 @@
import { ChatRecordData, CreateLinkEvent } from '@nitrots/nitro-renderer'; import { ChatRecordData, CreateLinkEvent } from '@nitrots/nitro-renderer';
import { FC, useMemo } from 'react'; import { FC, useMemo } from 'react';
import { TryVisitRoom } from '../../../../api'; import { LocalizeText, TryVisitRoom } from '../../../../api';
import { Button, Column, Flex, Grid, InfiniteScroll, Text } from '../../../../common'; import { Button, Column, Flex, Grid, InfiniteScroll, Text } from '../../../../common';
import { useModTools } from '../../../../hooks'; import { useModTools } from '../../../../hooks';
import { ChatlogRecord } from './ChatlogRecord'; import { ChatlogRecord } from './ChatlogRecord';
@@ -49,8 +49,8 @@ export const ChatlogView: FC<ChatlogViewProps> = props =>
<Flex alignItems="center" className="bg-muted rounded p-2" gap={ 2 } justifyContent="between"> <Flex alignItems="center" className="bg-muted rounded p-2" gap={ 2 } justifyContent="between">
<Text bold truncate>{ props.roomName }</Text> <Text bold truncate>{ props.roomName }</Text>
<div className="flex gap-1 shrink-0"> <div className="flex gap-1 shrink-0">
<Button size="sm" onClick={ event => TryVisitRoom(props.roomId) }>Visit</Button> <Button size="sm" onClick={ event => TryVisitRoom(props.roomId) }>{ LocalizeText('moderation.chatlog.visit') }</Button>
<Button size="sm" onClick={ event => openRoomInfo(props.roomId) }>Room Tools</Button> <Button size="sm" onClick={ event => openRoomInfo(props.roomId) }>{ LocalizeText('moderation.chatlog.roomtools') }</Button>
</div> </div>
</Flex> </Flex>
); );
@@ -61,9 +61,9 @@ export const ChatlogView: FC<ChatlogViewProps> = props =>
<Column fit gap={ 0 } overflow="hidden"> <Column fit gap={ 0 } overflow="hidden">
<Column gap={ 2 }> <Column gap={ 2 }>
<Grid className="text-black font-bold border-bottom pb-1 text-[11px] uppercase opacity-60 tracking-wider" gap={ 1 }> <Grid className="text-black font-bold border-bottom pb-1 text-[11px] uppercase opacity-60 tracking-wider" gap={ 1 }>
<div className="col-span-2">Time</div> <div className="col-span-2">{ LocalizeText('moderation.chatlog.col.time') }</div>
<div className="col-span-3">User</div> <div className="col-span-3">{ LocalizeText('moderation.chatlog.col.user') }</div>
<div className="col-span-7">Message</div> <div className="col-span-7">{ LocalizeText('moderation.chatlog.col.message') }</div>
</Grid> </Grid>
</Column> </Column>
{ (records && (records.length > 0)) && { (records && (records.length > 0)) &&
@@ -1,6 +1,6 @@
import { ChatRecordData, GetRoomChatlogMessageComposer, RoomChatlogEvent } from '@nitrots/nitro-renderer'; import { ChatRecordData, GetRoomChatlogMessageComposer, RoomChatlogEvent } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import { SendMessageComposer } from '../../../../api'; import { LocalizeText, SendMessageComposer } from '../../../../api';
import { DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common'; import { DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
import { useMessageEvent } from '../../../../hooks'; import { useMessageEvent } from '../../../../hooks';
import { ChatlogView } from '../chatlog/ChatlogView'; import { ChatlogView } from '../chatlog/ChatlogView';
@@ -34,7 +34,7 @@ export const ModToolsChatlogView: FC<ModToolsChatlogViewProps> = props =>
return ( return (
<NitroCardView className="nitro-mod-tools-chatlog min-w-[400px] max-h-[500px]" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }> <NitroCardView className="nitro-mod-tools-chatlog min-w-[400px] max-h-[500px]" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }>
<NitroCardHeaderView headerText={ `Room Chatlog` } onCloseClick={ onCloseClick } /> <NitroCardHeaderView headerText={ LocalizeText('moderation.chatlog.room') } onCloseClick={ onCloseClick } />
<NitroCardContentView className="text-black" overflow="auto"> <NitroCardContentView className="text-black" overflow="auto">
{ roomChatlog && { roomChatlog &&
<ChatlogView records={ [ roomChatlog ] } /> } <ChatlogView records={ [ roomChatlog ] } /> }
@@ -1,6 +1,6 @@
import { CreateLinkEvent, GetModeratorRoomInfoMessageComposer, ModerateRoomMessageComposer, ModeratorActionMessageComposer, ModeratorRoomInfoEvent } from '@nitrots/nitro-renderer'; import { CreateLinkEvent, GetModeratorRoomInfoMessageComposer, ModerateRoomMessageComposer, ModeratorActionMessageComposer, ModeratorRoomInfoEvent } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import { SendMessageComposer, TryVisitRoom } from '../../../../api'; import { LocalizeText, SendMessageComposer, TryVisitRoom } from '../../../../api';
import { Button, Column, DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; import { Button, Column, DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { useMessageEvent } from '../../../../hooks'; import { useMessageEvent } from '../../../../hooks';
@@ -70,7 +70,7 @@ export const ModToolsRoomView: FC<ModToolsRoomViewProps> = props =>
return ( return (
<NitroCardView className="nitro-mod-tools-room min-w-[280px]" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }> <NitroCardView className="nitro-mod-tools-room min-w-[280px]" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }>
<NitroCardHeaderView headerText={ 'Room Info' } onCloseClick={ event => onCloseClick() } /> <NitroCardHeaderView headerText={ LocalizeText('moderation.roomtool.info.title') } onCloseClick={ event => onCloseClick() } />
<NitroCardContentView className="text-black" gap={ 2 }> <NitroCardContentView className="text-black" gap={ 2 }>
{ name && { name &&
<div className="bg-muted rounded px-2 py-1.5 text-center"> <div className="bg-muted rounded px-2 py-1.5 text-center">
@@ -80,41 +80,41 @@ export const ModToolsRoomView: FC<ModToolsRoomViewProps> = props =>
<div className="flex gap-2"> <div className="flex gap-2">
<Column grow gap={ 1 }> <Column grow gap={ 1 }>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<Text bold className="opacity-60 shrink-0">Owner:</Text> <Text bold className="opacity-60 shrink-0">{ LocalizeText('moderation.roomtool.roomowner.title') }</Text>
<Text bold pointer truncate underline onClick={ () => CreateLinkEvent(`mod-tools/open-user-info/${ ownerId }`) }>{ ownerName }</Text> <Text bold pointer truncate underline onClick={ () => CreateLinkEvent(`mod-tools/open-user-info/${ ownerId }`) }>{ ownerName }</Text>
</div> </div>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<Text bold className="opacity-60 shrink-0">Users in room:</Text> <Text bold className="opacity-60 shrink-0">{ LocalizeText('moderation.roomtool.usersinroom.title') }</Text>
<Text>{ usersInRoom }</Text> <Text>{ usersInRoom }</Text>
</div> </div>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<Text bold className="opacity-60 shrink-0">Owner here:</Text> <Text bold className="opacity-60 shrink-0">{ LocalizeText('moderation.roomtool.ownerinroom.title') }</Text>
<Text className={ ownerInRoom ? 'text-green-700' : 'text-red-700' }>{ ownerInRoom ? 'Yes' : 'No' }</Text> <Text className={ ownerInRoom ? 'text-green-700' : 'text-red-700' }>{ ownerInRoom ? LocalizeText('moderation.roomtool.true.title') : LocalizeText('moderation.roomtool.false.title') }</Text>
</div> </div>
</Column> </Column>
<div className="flex flex-col gap-1 shrink-0"> <div className="flex flex-col gap-1 shrink-0">
<Button onClick={ event => TryVisitRoom(roomId) }>Visit Room</Button> <Button onClick={ event => TryVisitRoom(roomId) }>{ LocalizeText('moderation.roomtool.button.visit.title') }</Button>
<Button onClick={ event => CreateLinkEvent(`mod-tools/open-room-chatlog/${ roomId }`) }>Chatlog</Button> <Button onClick={ event => CreateLinkEvent(`mod-tools/open-room-chatlog/${ roomId }`) }>{ LocalizeText('moderation.modtools.roomchatlogs') }</Button>
</div> </div>
</div> </div>
<Column className="bg-muted rounded p-2" gap={ 1 }> <Column className="bg-muted rounded p-2" gap={ 1 }>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<input checked={ kickUsers } className="form-check-input" type="checkbox" onChange={ event => setKickUsers(event.target.checked) } /> <input checked={ kickUsers } className="form-check-input" type="checkbox" onChange={ event => setKickUsers(event.target.checked) } />
<Text small>Kick everyone out</Text> <Text small>{ LocalizeText('moderation.roomtool.kickall.title') }</Text>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<input checked={ lockRoom } className="form-check-input" type="checkbox" onChange={ event => setLockRoom(event.target.checked) } /> <input checked={ lockRoom } className="form-check-input" type="checkbox" onChange={ event => setLockRoom(event.target.checked) } />
<Text small>Enable the doorbell</Text> <Text small>{ LocalizeText('moderation.roomtool.closeroom.title') }</Text>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<input checked={ changeRoomName } className="form-check-input" type="checkbox" onChange={ event => setChangeRoomName(event.target.checked) } /> <input checked={ changeRoomName } className="form-check-input" type="checkbox" onChange={ event => setChangeRoomName(event.target.checked) } />
<Text small>Change room name</Text> <Text small>{ LocalizeText('moderation.roomtool.inappropiatename.title') }</Text>
</div> </div>
</Column> </Column>
<textarea className="min-h-[60px] px-2 py-1.5 rounded text-sm border border-black/10" placeholder="Type a mandatory message..." value={ message } onChange={ event => setMessage(event.target.value) }></textarea> <textarea className="min-h-[60px] px-2 py-1.5 rounded text-sm border border-black/10" placeholder={ LocalizeText('moderation.roomtool.presets.title') } value={ message } onChange={ event => setMessage(event.target.value) }></textarea>
<div className="flex gap-2"> <div className="flex gap-2">
<Button className="grow" variant="danger" onClick={ event => handleClick('send_message') }>Send Caution</Button> <Button className="grow" variant="danger" onClick={ event => handleClick('send_message') }>{ LocalizeText('moderation.roomtool.button.caution.title') }</Button>
<Button className="grow" onClick={ event => handleClick('alert_only') }>Send Alert</Button> <Button className="grow" onClick={ event => handleClick('alert_only') }>{ LocalizeText('moderation.roomtool.button.message.title') }</Button>
</div> </div>
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> </NitroCardView>
@@ -1,6 +1,6 @@
import { CfhChatlogData, CfhChatlogEvent, GetCfhChatlogMessageComposer } from '@nitrots/nitro-renderer'; import { CfhChatlogData, CfhChatlogEvent, GetCfhChatlogMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import { SendMessageComposer } from '../../../../api'; import { LocalizeText, SendMessageComposer } from '../../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
import { useMessageEvent } from '../../../../hooks'; import { useMessageEvent } from '../../../../hooks';
import { ChatlogView } from '../chatlog/ChatlogView'; import { ChatlogView } from '../chatlog/ChatlogView';
@@ -32,7 +32,7 @@ export const CfhChatlogView: FC<CfhChatlogViewProps> = props =>
return ( return (
<NitroCardView className="nitro-mod-tools-chatlog" theme="primary-slim"> <NitroCardView className="nitro-mod-tools-chatlog" theme="primary-slim">
<NitroCardHeaderView headerText={ 'Issue Chatlog' } onCloseClick={ onCloseClick } /> <NitroCardHeaderView headerText={ LocalizeText('moderation.chatlog.issue') } onCloseClick={ onCloseClick } />
<NitroCardContentView className="text-black"> <NitroCardContentView className="text-black">
{ chatlogData && <ChatlogView records={ [ chatlogData.chatRecord ] } /> } { chatlogData && <ChatlogView records={ [ chatlogData.chatRecord ] } /> }
</NitroCardContentView> </NitroCardContentView>
@@ -35,33 +35,33 @@ export const ModToolsIssueInfoView: FC<IssueInfoViewProps> = props =>
return ( return (
<> <>
<NitroCardView className="nitro-mod-tools-handle-issue" theme="primary-slim"> <NitroCardView className="nitro-mod-tools-handle-issue" theme="primary-slim">
<NitroCardHeaderView headerText={ 'Resolving issue ' + issueId } onCloseClick={ () => onIssueInfoClosed(issueId) } /> <NitroCardHeaderView headerText={ LocalizeText('moderation.issue.resolving', [ 'id' ], [ String(issueId) ]) } onCloseClick={ () => onIssueInfoClosed(issueId) } />
<NitroCardContentView className="text-black"> <NitroCardContentView className="text-black">
<Text fontSize={ 4 }>Issue Information</Text> <Text fontSize={ 4 }>{ LocalizeText('moderation.issue.info') }</Text>
<Grid overflow="auto"> <Grid overflow="auto">
<Column size={ 8 }> <Column size={ 8 }>
<table className="table table-striped table-sm table-text-small text-black m-0"> <table className="table table-striped table-sm table-text-small text-black m-0">
<tbody> <tbody>
<tr> <tr>
<th>Source</th> <th>{ LocalizeText('moderation.issue.source') }</th>
<td>{ GetIssueCategoryName(ticket.categoryId) }</td> <td>{ GetIssueCategoryName(ticket.categoryId) }</td>
</tr> </tr>
<tr> <tr>
<th>Category</th> <th>{ LocalizeText('moderation.issue.category') }</th>
<td className="text-break">{ LocalizeText('help.cfh.topic.' + ticket.reportedCategoryId) }</td> <td className="text-break">{ LocalizeText('help.cfh.topic.' + ticket.reportedCategoryId) }</td>
</tr> </tr>
<tr> <tr>
<th>Description</th> <th>{ LocalizeText('moderation.issue.description') }</th>
<td className="text-break">{ ticket.message }</td> <td className="text-break">{ ticket.message }</td>
</tr> </tr>
<tr> <tr>
<th>Caller</th> <th>{ LocalizeText('moderation.issue.caller') }</th>
<td> <td>
<Text bold pointer underline onClick={ event => openUserInfo(ticket.reporterUserId) }>{ ticket.reporterUserName }</Text> <Text bold pointer underline onClick={ event => openUserInfo(ticket.reporterUserId) }>{ ticket.reporterUserName }</Text>
</td> </td>
</tr> </tr>
<tr> <tr>
<th>Reported User</th> <th>{ LocalizeText('moderation.issue.reported') }</th>
<td> <td>
<Text bold pointer underline onClick={ event => openUserInfo(ticket.reportedUserId) }>{ ticket.reportedUserName }</Text> <Text bold pointer underline onClick={ event => openUserInfo(ticket.reportedUserId) }>{ ticket.reportedUserName }</Text>
</td> </td>
@@ -70,11 +70,11 @@ export const ModToolsIssueInfoView: FC<IssueInfoViewProps> = props =>
</table> </table>
</Column> </Column>
<Column gap={ 1 } size={ 4 }> <Column gap={ 1 } size={ 4 }>
<Button variant="secondary" onClick={ () => setcfhChatlogOpen(!cfhChatlogOpen) }>Chatlog</Button> <Button variant="secondary" onClick={ () => setcfhChatlogOpen(!cfhChatlogOpen) }>{ LocalizeText('moderation.issue.chatlog') }</Button>
<Button onClick={ event => closeIssue(CloseIssuesMessageComposer.RESOLUTION_USELESS) }>Close as useless</Button> <Button onClick={ event => closeIssue(CloseIssuesMessageComposer.RESOLUTION_USELESS) }>{ LocalizeText('moderation.issue.close.useless') }</Button>
<Button variant="danger" onClick={ event => closeIssue(CloseIssuesMessageComposer.RESOLUTION_ABUSIVE) }>Close as abusive</Button> <Button variant="danger" onClick={ event => closeIssue(CloseIssuesMessageComposer.RESOLUTION_ABUSIVE) }>{ LocalizeText('moderation.issue.close.abusive') }</Button>
<Button variant="success" onClick={ event => closeIssue(CloseIssuesMessageComposer.RESOLUTION_RESOLVED) }>Close as resolved</Button> <Button variant="success" onClick={ event => closeIssue(CloseIssuesMessageComposer.RESOLUTION_RESOLVED) }>{ LocalizeText('moderation.issue.close.resolved') }</Button>
<Button variant="secondary" onClick={ event => releaseIssue(issueId) } >Release</Button> <Button variant="secondary" onClick={ event => releaseIssue(issueId) } >{ LocalizeText('moderation.issue.release') }</Button>
</Column> </Column>
</Grid> </Grid>
</NitroCardContentView> </NitroCardContentView>
@@ -1,6 +1,6 @@
import { IssueMessageData, ReleaseIssuesMessageComposer } from '@nitrots/nitro-renderer'; import { IssueMessageData, ReleaseIssuesMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useRef } from 'react'; import { FC, useRef } from 'react';
import { SendMessageComposer } from '../../../../api'; import { LocalizeText, SendMessageComposer } from '../../../../api';
import { Button, Column, Grid } from '../../../../common'; import { Button, Column, Grid } from '../../../../common';
interface ModToolsMyIssuesTabViewProps interface ModToolsMyIssuesTabViewProps
@@ -28,9 +28,9 @@ export const ModToolsMyIssuesTabView: FC<ModToolsMyIssuesTabViewProps> = props =
<Column gap={ 0 } overflow="hidden"> <Column gap={ 0 } overflow="hidden">
<Column gap={ 2 }> <Column gap={ 2 }>
<Grid className="text-black font-bold border-bottom pb-1" gap={ 1 }> <Grid className="text-black font-bold border-bottom pb-1" gap={ 1 }>
<div className="col-span-2">Type</div> <div className="col-span-2">{ LocalizeText('moderation.tickets.col.type') }</div>
<div className="col-span-3">Room/Player</div> <div className="col-span-3">{ LocalizeText('moderation.tickets.col.roomPlayer') }</div>
<div className="col-span-3">Opened</div> <div className="col-span-3">{ LocalizeText('moderation.tickets.col.opened') }</div>
<div className="col-span-2"></div> <div className="col-span-2"></div>
<div className="col-span-2"></div> <div className="col-span-2"></div>
</Grid> </Grid>
@@ -44,10 +44,10 @@ export const ModToolsMyIssuesTabView: FC<ModToolsMyIssuesTabViewProps> = props =
<div className="col-span-3">{ issue.reportedUserName }</div> <div className="col-span-3">{ issue.reportedUserName }</div>
<div className="col-span-3">{ new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString() }</div> <div className="col-span-3">{ new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString() }</div>
<div className="col-span-2"> <div className="col-span-2">
<Button variant="primary" onClick={ event => handleIssue(issue.issueId) }>Handle</Button> <Button variant="primary" onClick={ event => handleIssue(issue.issueId) }>{ LocalizeText('moderation.tickets.handle') }</Button>
</div> </div>
<div className="col-span-2"> <div className="col-span-2">
<Button variant="danger" onClick={ () => releaseIssue(issue.issueId) }>Release</Button> <Button variant="danger" onClick={ () => releaseIssue(issue.issueId) }>{ LocalizeText('moderation.tickets.release') }</Button>
</div> </div>
</Grid> </Grid>
); );
@@ -1,6 +1,6 @@
import { IssueMessageData, PickIssuesMessageComposer } from '@nitrots/nitro-renderer'; import { IssueMessageData, PickIssuesMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useRef } from 'react'; import { FC, useRef } from 'react';
import { SendMessageComposer } from '../../../../api'; import { LocalizeText, SendMessageComposer } from '../../../../api';
import { Button, Column, Grid } from '../../../../common'; import { Button, Column, Grid } from '../../../../common';
interface ModToolsOpenIssuesTabViewProps interface ModToolsOpenIssuesTabViewProps
@@ -27,9 +27,9 @@ export const ModToolsOpenIssuesTabView: FC<ModToolsOpenIssuesTabViewProps> = pro
<Column gap={ 0 } overflow="hidden"> <Column gap={ 0 } overflow="hidden">
<Column gap={ 2 }> <Column gap={ 2 }>
<Grid className="text-black font-bold border-bottom pb-1" gap={ 1 }> <Grid className="text-black font-bold border-bottom pb-1" gap={ 1 }>
<div className="col-span-2">Type</div> <div className="col-span-2">{ LocalizeText('moderation.tickets.col.type') }</div>
<div className="col-span-3">Room/Player</div> <div className="col-span-3">{ LocalizeText('moderation.tickets.col.roomPlayer') }</div>
<div className="col-span-4">Opened</div> <div className="col-span-4">{ LocalizeText('moderation.tickets.col.opened') }</div>
<div className="col-span-3"></div> <div className="col-span-3"></div>
</Grid> </Grid>
</Column> </Column>
@@ -42,7 +42,7 @@ export const ModToolsOpenIssuesTabView: FC<ModToolsOpenIssuesTabViewProps> = pro
<div className="col-span-3">{ issue.reportedUserName }</div> <div className="col-span-3">{ issue.reportedUserName }</div>
<div className="col-span-4">{ new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString() }</div> <div className="col-span-4">{ new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString() }</div>
<div className="col-span-3"> <div className="col-span-3">
<Button variant="success" onClick={ () => pickIssue(issue.issueId) }>Pick Issue</Button> <Button variant="success" onClick={ () => pickIssue(issue.issueId) }>{ LocalizeText('moderation.tickets.pick') }</Button>
</div> </div>
</Grid> </Grid>
); );
@@ -1,5 +1,6 @@
import { IssueMessageData } from '@nitrots/nitro-renderer'; import { IssueMessageData } from '@nitrots/nitro-renderer';
import { FC } from 'react'; import { FC } from 'react';
import { LocalizeText } from '../../../../api';
import { Column, Grid } from '../../../../common'; import { Column, Grid } from '../../../../common';
interface ModToolsPickedIssuesTabViewProps interface ModToolsPickedIssuesTabViewProps
@@ -15,10 +16,10 @@ export const ModToolsPickedIssuesTabView: FC<ModToolsPickedIssuesTabViewProps> =
<Column gap={ 0 } overflow="hidden"> <Column gap={ 0 } overflow="hidden">
<Column gap={ 2 }> <Column gap={ 2 }>
<Grid className="text-black font-bold border-bottom pb-1" gap={ 1 }> <Grid className="text-black font-bold border-bottom pb-1" gap={ 1 }>
<div className="col-span-2">Type</div> <div className="col-span-2">{ LocalizeText('moderation.tickets.col.type') }</div>
<div className="col-span-3">Room/Player</div> <div className="col-span-3">{ LocalizeText('moderation.tickets.col.roomPlayer') }</div>
<div className="col-span-4">Opened</div> <div className="col-span-4">{ LocalizeText('moderation.tickets.col.opened') }</div>
<div className="col-span-3">Picker</div> <div className="col-span-3">{ LocalizeText('moderation.tickets.col.picker') }</div>
</Grid> </Grid>
</Column> </Column>
<Column className="striped-children" gap={ 0 } overflow="auto"> <Column className="striped-children" gap={ 0 } overflow="auto">
@@ -1,5 +1,6 @@
import { GetSessionDataManager, IssueMessageData } from '@nitrots/nitro-renderer'; import { GetSessionDataManager, IssueMessageData } from '@nitrots/nitro-renderer';
import { FC, useState } from 'react'; import { FC, useState } from 'react';
import { LocalizeText } from '../../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../common'; import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../common';
import { useModTools } from '../../../../hooks'; import { useModTools } from '../../../../hooks';
import { ModToolsIssueInfoView } from './ModToolsIssueInfoView'; import { ModToolsIssueInfoView } from './ModToolsIssueInfoView';
@@ -12,10 +13,10 @@ interface ModToolsTicketsViewProps
onCloseClick: () => void; onCloseClick: () => void;
} }
const TABS: string[] = [ const TAB_KEYS: string[] = [
'Open Issues', 'moderation.tickets.open',
'My Issues', 'moderation.tickets.my',
'Picked Issues' 'moderation.tickets.picked'
]; ];
export const ModToolsTicketsView: FC<ModToolsTicketsViewProps> = props => export const ModToolsTicketsView: FC<ModToolsTicketsViewProps> = props =>
@@ -71,12 +72,12 @@ export const ModToolsTicketsView: FC<ModToolsTicketsViewProps> = props =>
return ( return (
<> <>
<NitroCardView className="nitro-mod-tools-tickets"> <NitroCardView className="nitro-mod-tools-tickets">
<NitroCardHeaderView headerText={ 'Tickets' } onCloseClick={ onCloseClick } /> <NitroCardHeaderView headerText={ LocalizeText('moderation.tickets.title') } onCloseClick={ onCloseClick } />
<NitroCardTabsView> <NitroCardTabsView>
{ TABS.map((tab, index) => { TAB_KEYS.map((tabKey, index) =>
{ {
return (<NitroCardTabsItemView key={ index } isActive={ (currentTab === index) } onClick={ event => setCurrentTab(index) }> return (<NitroCardTabsItemView key={ index } isActive={ (currentTab === index) } onClick={ event => setCurrentTab(index) }>
{ tab } { LocalizeText(tabKey) }
</NitroCardTabsItemView>); </NitroCardTabsItemView>);
}) } }) }
</NitroCardTabsView> </NitroCardTabsView>
@@ -1,6 +1,6 @@
import { ChatRecordData, GetUserChatlogMessageComposer, UserChatlogEvent } from '@nitrots/nitro-renderer'; import { ChatRecordData, GetUserChatlogMessageComposer, UserChatlogEvent } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import { SendMessageComposer } from '../../../../api'; import { LocalizeText, SendMessageComposer } from '../../../../api';
import { DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common'; import { DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
import { useMessageEvent } from '../../../../hooks'; import { useMessageEvent } from '../../../../hooks';
import { ChatlogView } from '../chatlog/ChatlogView'; import { ChatlogView } from '../chatlog/ChatlogView';
@@ -34,7 +34,7 @@ export const ModToolsUserChatlogView: FC<ModToolsUserChatlogViewProps> = props =
return ( return (
<NitroCardView className="nitro-mod-tools-chatlog" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }> <NitroCardView className="nitro-mod-tools-chatlog" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }>
<NitroCardHeaderView headerText={ `User Chatlog: ${ username || '' }` } onCloseClick={ onCloseClick } /> <NitroCardHeaderView headerText={ LocalizeText('moderation.chatlog.user', [ 'username' ], [ username || '' ]) } onCloseClick={ onCloseClick } />
<NitroCardContentView className="text-black h-full"> <NitroCardContentView className="text-black h-full">
{ userChatlog && { userChatlog &&
<ChatlogView records={ userChatlog } /> } <ChatlogView records={ userChatlog } /> }
@@ -11,18 +11,18 @@ interface ModToolsUserModActionViewProps
} }
const MOD_ACTION_DEFINITIONS = [ const MOD_ACTION_DEFINITIONS = [
new ModActionDefinition(1, 'Alert', ModActionDefinition.ALERT, 1, 0), new ModActionDefinition(1, 'moderation.modaction.alert', ModActionDefinition.ALERT, 1, 0),
new ModActionDefinition(2, 'Mute 1h', ModActionDefinition.MUTE, 2, 0), new ModActionDefinition(2, 'moderation.modaction.mute1h', ModActionDefinition.MUTE, 2, 0),
new ModActionDefinition(3, 'Ban 18h', ModActionDefinition.BAN, 3, 0), new ModActionDefinition(3, 'moderation.modaction.ban18h', ModActionDefinition.BAN, 3, 0),
new ModActionDefinition(4, 'Ban 7 days', ModActionDefinition.BAN, 4, 0), new ModActionDefinition(4, 'moderation.modaction.ban7days', ModActionDefinition.BAN, 4, 0),
new ModActionDefinition(5, 'Ban 30 days (step 1)', ModActionDefinition.BAN, 5, 0), new ModActionDefinition(5, 'moderation.modaction.ban30days.step1', ModActionDefinition.BAN, 5, 0),
new ModActionDefinition(7, 'Ban 30 days (step 2)', ModActionDefinition.BAN, 7, 0), new ModActionDefinition(7, 'moderation.modaction.ban30days.step2', ModActionDefinition.BAN, 7, 0),
new ModActionDefinition(6, 'Ban 100 years', ModActionDefinition.BAN, 6, 0), new ModActionDefinition(6, 'moderation.modaction.ban100years', ModActionDefinition.BAN, 6, 0),
new ModActionDefinition(106, 'Ban avatar-only 100 years', ModActionDefinition.BAN, 6, 0), new ModActionDefinition(106, 'moderation.modaction.banavataronly100years', ModActionDefinition.BAN, 6, 0),
new ModActionDefinition(101, 'Kick', ModActionDefinition.KICK, 0, 0), new ModActionDefinition(101, 'moderation.modaction.kick', ModActionDefinition.KICK, 0, 0),
new ModActionDefinition(102, 'Lock trade 1 week', ModActionDefinition.TRADE_LOCK, 0, 168), new ModActionDefinition(102, 'moderation.modaction.locktrade1week', ModActionDefinition.TRADE_LOCK, 0, 168),
new ModActionDefinition(104, 'Lock trade permanent', ModActionDefinition.TRADE_LOCK, 0, 876000), new ModActionDefinition(104, 'moderation.modaction.locktradepermanent', ModActionDefinition.TRADE_LOCK, 0, 876000),
new ModActionDefinition(105, 'Message', ModActionDefinition.MESSAGE, 0, 0), new ModActionDefinition(105, 'moderation.modaction.message', ModActionDefinition.MESSAGE, 0, 0),
]; ];
export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = props => export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = props =>
@@ -60,7 +60,7 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
const category = topics[selectedTopic]; const category = topics[selectedTopic];
if(selectedTopic === -1) errorMessage = 'You must select a CFH topic'; if(selectedTopic === -1) errorMessage = LocalizeText('moderation.modaction.error.notopic');
if(errorMessage) return sendAlert(errorMessage); if(errorMessage) return sendAlert(errorMessage);
@@ -82,10 +82,10 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
const category = topics[selectedTopic]; const category = topics[selectedTopic];
const sanction = MOD_ACTION_DEFINITIONS[selectedAction]; const sanction = MOD_ACTION_DEFINITIONS[selectedAction];
if((selectedTopic === -1) || (selectedAction === -1)) errorMessage = 'You must select a CFH topic and Sanction'; if((selectedTopic === -1) || (selectedAction === -1)) errorMessage = LocalizeText('moderation.modaction.error.notopicorsanction');
else if(!settings || !settings.cfhPermission) errorMessage = 'You do not have permission to do this'; else if(!settings || !settings.cfhPermission) errorMessage = LocalizeText('moderation.modaction.error.nopermission');
else if(!category) errorMessage = 'You must select a CFH topic'; else if(!category) errorMessage = LocalizeText('moderation.modaction.error.notopic');
else if(!sanction) errorMessage = 'You must select a sanction'; else if(!sanction) errorMessage = LocalizeText('moderation.modaction.error.nosanction');
if(errorMessage) if(errorMessage)
{ {
@@ -101,7 +101,7 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
case ModActionDefinition.ALERT: { case ModActionDefinition.ALERT: {
if(!settings.alertPermission) if(!settings.alertPermission)
{ {
sendAlert('You have insufficient permissions'); sendAlert(LocalizeText('moderation.modaction.error.nopermission'));
return; return;
} }
@@ -115,7 +115,7 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
case ModActionDefinition.BAN: { case ModActionDefinition.BAN: {
if(!settings.banPermission) if(!settings.banPermission)
{ {
sendAlert('You have insufficient permissions'); sendAlert(LocalizeText('moderation.modaction.error.nopermission'));
return; return;
} }
@@ -126,7 +126,7 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
case ModActionDefinition.KICK: { case ModActionDefinition.KICK: {
if(!settings.kickPermission) if(!settings.kickPermission)
{ {
sendAlert('You have insufficient permissions'); sendAlert(LocalizeText('moderation.modaction.error.nopermission'));
return; return;
} }
@@ -142,7 +142,7 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
case ModActionDefinition.MESSAGE: { case ModActionDefinition.MESSAGE: {
if(message.trim().length === 0) if(message.trim().length === 0)
{ {
sendAlert('Please write a message to user'); sendAlert(LocalizeText('moderation.modaction.error.emptymessage'));
return; return;
} }
@@ -161,23 +161,23 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
return ( return (
<NitroCardView className="nitro-mod-tools-user-action" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }> <NitroCardView className="nitro-mod-tools-user-action" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }>
<NitroCardHeaderView headerText={ 'Mod Action: ' + (user ? user.username : '') } onCloseClick={ () => onCloseClick() } /> <NitroCardHeaderView headerText={ LocalizeText('moderation.modaction.title', [ 'username' ], [ user ? user.username : '' ]) } onCloseClick={ () => onCloseClick() } />
<NitroCardContentView className="text-black"> <NitroCardContentView className="text-black">
<select className="form-select form-select-sm" value={ selectedTopic } onChange={ event => setSelectedTopic(parseInt(event.target.value)) }> <select className="form-select form-select-sm" value={ selectedTopic } onChange={ event => setSelectedTopic(parseInt(event.target.value)) }>
<option disabled value={ -1 }>CFH Topic</option> <option disabled value={ -1 }>{ LocalizeText('moderation.modaction.cfhtopic') }</option>
{ topics.map((topic, index) => <option key={ index } value={ index }>{ LocalizeText('help.cfh.topic.' + topic.id) }</option>) } { topics.map((topic, index) => <option key={ index } value={ index }>{ LocalizeText('help.cfh.topic.' + topic.id) }</option>) }
</select> </select>
<select className="form-select form-select-sm" value={ selectedAction } onChange={ event => setSelectedAction(parseInt(event.target.value)) }> <select className="form-select form-select-sm" value={ selectedAction } onChange={ event => setSelectedAction(parseInt(event.target.value)) }>
<option disabled value={ -1 }>Sanction Type</option> <option disabled value={ -1 }>{ LocalizeText('moderation.modaction.sanctiontype') }</option>
{ MOD_ACTION_DEFINITIONS.map((action, index) => <option key={ index } value={ index }>{ action.name }</option>) } { MOD_ACTION_DEFINITIONS.map((action, index) => <option key={ index } value={ index }>{ LocalizeText(action.name) }</option>) }
</select> </select>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<Text small>Optional message type, overrides default</Text> <Text small>{ LocalizeText('moderation.modaction.message.hint') }</Text>
<textarea className="min-h-[calc(1.5em+ .5rem+2px)] px-[.5rem] py-[.25rem] rounded-[.2rem]" value={ message } onChange={ event => setMessage(event.target.value) } /> <textarea className="min-h-[calc(1.5em+ .5rem+2px)] px-[.5rem] py-[.25rem] rounded-[.2rem]" value={ message } onChange={ event => setMessage(event.target.value) } />
</div> </div>
<Flex gap={ 1 } justifyContent="between"> <Flex gap={ 1 } justifyContent="between">
<Button variant="primary" onClick={ sendDefaultSanction }>Default Sanction</Button> <Button variant="primary" onClick={ sendDefaultSanction }>{ LocalizeText('moderation.modaction.defaultsanction') }</Button>
<Button variant="success" onClick={ sendSanction }>Sanction</Button> <Button variant="success" onClick={ sendSanction }>{ LocalizeText('moderation.modaction.sanction') }</Button>
</Flex> </Flex>
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> </NitroCardView>
@@ -1,6 +1,6 @@
import { GetRoomVisitsMessageComposer, RoomVisitsData, RoomVisitsEvent } from '@nitrots/nitro-renderer'; import { GetRoomVisitsMessageComposer, RoomVisitsData, RoomVisitsEvent } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import { SendMessageComposer, TryVisitRoom } from '../../../../api'; import { LocalizeText, SendMessageComposer, TryVisitRoom } from '../../../../api';
import { Column, DraggableWindowPosition, Grid, InfiniteScroll, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; import { Column, DraggableWindowPosition, Grid, InfiniteScroll, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { useMessageEvent } from '../../../../hooks'; import { useMessageEvent } from '../../../../hooks';
@@ -33,14 +33,14 @@ export const ModToolsUserRoomVisitsView: FC<ModToolsUserRoomVisitsViewProps> = p
return ( return (
<NitroCardView className="nitro-mod-tools-user-visits" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }> <NitroCardView className="nitro-mod-tools-user-visits" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }>
<NitroCardHeaderView headerText={ 'User Visits' } onCloseClick={ onCloseClick } /> <NitroCardHeaderView headerText={ LocalizeText('moderation.roomvisits.title') } onCloseClick={ onCloseClick } />
<NitroCardContentView className="text-black" gap={ 1 }> <NitroCardContentView className="text-black" gap={ 1 }>
<Column fullHeight gap={ 0 } overflow="hidden"> <Column fullHeight gap={ 0 } overflow="hidden">
<Column gap={ 2 }> <Column gap={ 2 }>
<Grid className="text-black font-bold border-bottom pb-1" gap={ 1 }> <Grid className="text-black font-bold border-bottom pb-1" gap={ 1 }>
<div className="col-span-2">Time</div> <div className="col-span-2">{ LocalizeText('moderation.roomvisits.col.time') }</div>
<div className="col-span-7">Room name</div> <div className="col-span-7">{ LocalizeText('moderation.roomvisits.col.roomname') }</div>
<div className="col-span-3">Visit</div> <div className="col-span-3">{ LocalizeText('moderation.roomvisits.col.visit') }</div>
</Grid> </Grid>
</Column> </Column>
<InfiniteScroll rowRender={ row => <InfiniteScroll rowRender={ row =>
@@ -49,7 +49,7 @@ export const ModToolsUserRoomVisitsView: FC<ModToolsUserRoomVisitsViewProps> = p
<Grid alignItems="center" className="text-black py-1 border-bottom" fullHeight={ false } gap={ 1 }> <Grid alignItems="center" className="text-black py-1 border-bottom" fullHeight={ false } gap={ 1 }>
<Text className="col-span-2">{ row.enterHour.toString().padStart(2, '0') }: { row.enterMinute.toString().padStart(2, '0') }</Text> <Text className="col-span-2">{ row.enterHour.toString().padStart(2, '0') }: { row.enterMinute.toString().padStart(2, '0') }</Text>
<Text className="col-span-7">{ row.roomName }</Text> <Text className="col-span-7">{ row.roomName }</Text>
<Text bold pointer underline className="col-span-3" variant="primary" onClick={ event => TryVisitRoom(row.roomId) }>Visit Room</Text> <Text bold pointer underline className="col-span-3" variant="primary" onClick={ event => TryVisitRoom(row.roomId) }>{ LocalizeText('moderation.roomvisits.visitroom') }</Text>
</Grid> </Grid>
); );
} } rows={ roomVisitData?.rooms ?? [] } /> } } rows={ roomVisitData?.rooms ?? [] } />
@@ -1,6 +1,6 @@
import { ModMessageMessageComposer } from '@nitrots/nitro-renderer'; import { ModMessageMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useState } from 'react'; import { FC, useState } from 'react';
import { ISelectedUser, SendMessageComposer } from '../../../../api'; import { ISelectedUser, LocalizeText, SendMessageComposer } from '../../../../api';
import { Button, DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; import { Button, DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { useNotification } from '../../../../hooks'; import { useNotification } from '../../../../hooks';
@@ -22,7 +22,7 @@ export const ModToolsUserSendMessageView: FC<ModToolsUserSendMessageViewProps> =
{ {
if(message.trim().length === 0) if(message.trim().length === 0)
{ {
simpleAlert('Please write a message to user.', null, null, null, 'Error', null); simpleAlert(LocalizeText('moderation.sendmessage.error.empty'), null, null, null, LocalizeText('moderation.error'), null);
return; return;
} }
@@ -34,11 +34,11 @@ export const ModToolsUserSendMessageView: FC<ModToolsUserSendMessageViewProps> =
return ( return (
<NitroCardView className="nitro-mod-tools-user-message" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }> <NitroCardView className="nitro-mod-tools-user-message" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }>
<NitroCardHeaderView headerText={ 'Send Message' } onCloseClick={ () => onCloseClick() } /> <NitroCardHeaderView headerText={ LocalizeText('moderation.sendmessage.title') } onCloseClick={ () => onCloseClick() } />
<NitroCardContentView className="text-black"> <NitroCardContentView className="text-black">
<Text>Message To: { user.username }</Text> <Text>{ LocalizeText('moderation.sendmessage.to', [ 'username' ], [ user.username ]) }</Text>
<textarea className="min-h-[calc(1.5em+ .5rem+2px)] px-[.5rem] py-[.25rem] rounded-[.2rem]" value={ message } onChange={ event => setMessage(event.target.value) }></textarea> <textarea className="min-h-[calc(1.5em+ .5rem+2px)] px-[.5rem] py-[.25rem] rounded-[.2rem]" value={ message } onChange={ event => setMessage(event.target.value) }></textarea>
<Button fullWidth onClick={ sendMessage }>Send message</Button> <Button fullWidth onClick={ sendMessage }>{ LocalizeText('moderation.sendmessage.send') }</Button>
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> </NitroCardView>
); );
@@ -27,60 +27,60 @@ export const ModToolsUserView: FC<ModToolsUserViewProps> = props =>
return [ return [
{ {
localeKey: 'modtools.userinfo.userName', localeKey: 'moderation.userinfo.userName',
value: userInfo.userName, value: userInfo.userName,
showOnline: true showOnline: true
}, },
{ {
localeKey: 'modtools.userinfo.cfhCount', localeKey: 'moderation.userinfo.cfhCount',
value: userInfo.cfhCount.toString() value: userInfo.cfhCount.toString()
}, },
{ {
localeKey: 'modtools.userinfo.abusiveCfhCount', localeKey: 'moderation.userinfo.abusiveCfhCount',
value: userInfo.abusiveCfhCount.toString() value: userInfo.abusiveCfhCount.toString()
}, },
{ {
localeKey: 'modtools.userinfo.cautionCount', localeKey: 'moderation.userinfo.cautionCount',
value: userInfo.cautionCount.toString() value: userInfo.cautionCount.toString()
}, },
{ {
localeKey: 'modtools.userinfo.banCount', localeKey: 'moderation.userinfo.banCount',
value: userInfo.banCount.toString() value: userInfo.banCount.toString()
}, },
{ {
localeKey: 'modtools.userinfo.lastSanctionTime', localeKey: 'moderation.userinfo.lastSanctionTime',
value: userInfo.lastSanctionTime value: userInfo.lastSanctionTime
}, },
{ {
localeKey: 'modtools.userinfo.tradingLockCount', localeKey: 'moderation.userinfo.tradingLockCount',
value: userInfo.tradingLockCount.toString() value: userInfo.tradingLockCount.toString()
}, },
{ {
localeKey: 'modtools.userinfo.tradingExpiryDate', localeKey: 'moderation.userinfo.tradingExpiryDate',
value: userInfo.tradingExpiryDate value: userInfo.tradingExpiryDate
}, },
{ {
localeKey: 'modtools.userinfo.minutesSinceLastLogin', localeKey: 'moderation.userinfo.minutesSinceLastLogin',
value: FriendlyTime.format(userInfo.minutesSinceLastLogin * 60, '.ago', 2) value: FriendlyTime.format(userInfo.minutesSinceLastLogin * 60, '.ago', 2)
}, },
{ {
localeKey: 'modtools.userinfo.lastPurchaseDate', localeKey: 'moderation.userinfo.lastPurchaseDate',
value: userInfo.lastPurchaseDate value: userInfo.lastPurchaseDate
}, },
{ {
localeKey: 'modtools.userinfo.primaryEmailAddress', localeKey: 'moderation.userinfo.primaryEmailAddress',
value: userInfo.primaryEmailAddress value: userInfo.primaryEmailAddress
}, },
{ {
localeKey: 'modtools.userinfo.identityRelatedBanCount', localeKey: 'moderation.userinfo.identityRelatedBanCount',
value: userInfo.identityRelatedBanCount.toString() value: userInfo.identityRelatedBanCount.toString()
}, },
{ {
localeKey: 'modtools.userinfo.registrationAgeInMinutes', localeKey: 'moderation.userinfo.registrationAgeInMinutes',
value: FriendlyTime.format(userInfo.registrationAgeInMinutes * 60, '.ago', 2) value: FriendlyTime.format(userInfo.registrationAgeInMinutes * 60, '.ago', 2)
}, },
{ {
localeKey: 'modtools.userinfo.userClassification', localeKey: 'moderation.userinfo.userClassification',
value: userInfo.userClassification value: userInfo.userClassification
} }
]; ];
@@ -105,7 +105,7 @@ export const ModToolsUserView: FC<ModToolsUserViewProps> = props =>
return ( return (
<> <>
<NitroCardView className="nitro-mod-tools-user" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }> <NitroCardView className="nitro-mod-tools-user" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }>
<NitroCardHeaderView headerText={ LocalizeText('modtools.userinfo.title', [ 'username' ], [ userInfo.userName ]) } onCloseClick={ () => onCloseClick() } /> <NitroCardHeaderView headerText={ LocalizeText('moderation.userinfo.title', [ 'username' ], [ userInfo.userName ]) } onCloseClick={ () => onCloseClick() } />
<NitroCardContentView className="text-black"> <NitroCardContentView className="text-black">
<Grid overflow="hidden"> <Grid overflow="hidden">
<Column overflow="auto" size={ 8 }> <Column overflow="auto" size={ 8 }>
@@ -130,16 +130,16 @@ export const ModToolsUserView: FC<ModToolsUserViewProps> = props =>
</Column> </Column>
<Column gap={ 1 } size={ 4 }> <Column gap={ 1 } size={ 4 }>
<Button onClick={ event => CreateLinkEvent(`mod-tools/open-user-chatlog/${ userId }`) }> <Button onClick={ event => CreateLinkEvent(`mod-tools/open-user-chatlog/${ userId }`) }>
Room Chat { LocalizeText('moderation.userinfo.roomchat') }
</Button> </Button>
<Button onClick={ event => setSendMessageVisible(!sendMessageVisible) }> <Button onClick={ event => setSendMessageVisible(!sendMessageVisible) }>
Send Message { LocalizeText('moderation.userinfo.sendmessage') }
</Button> </Button>
<Button onClick={ event => setRoomVisitsVisible(!roomVisitsVisible) }> <Button onClick={ event => setRoomVisitsVisible(!roomVisitsVisible) }>
Room Visits { LocalizeText('moderation.userinfo.roomvisits') }
</Button> </Button>
<Button onClick={ event => setModActionVisible(!modActionVisible) }> <Button onClick={ event => setModActionVisible(!modActionVisible) }>
Mod Action { LocalizeText('moderation.userinfo.modaction') }
</Button> </Button>
</Column> </Column>
</Grid> </Grid>