🆙 Init V3

This commit is contained in:
DuckieTM
2026-01-31 09:10:52 +01:00
commit 7feb10ab15
1733 changed files with 53405 additions and 0 deletions
@@ -0,0 +1,48 @@
import { FC, useState } from 'react';
import { LocalizeText, ReportState, ReportType } from '../../../api';
import { Button, Flex, Text } from '../../../common';
import { useHelp } from '../../../hooks';
export const DescribeReportView: FC<{}> = props =>
{
const [ message, setMessage ] = useState('');
const { activeReport = null, setActiveReport = null } = useHelp();
const submitMessage = () =>
{
if(message.length < 15) return;
setActiveReport(prevValue =>
{
const currentStep = ReportState.REPORT_SUMMARY;
return { ...prevValue, message, currentStep };
});
};
const back = () =>
{
setActiveReport(prevValue =>
{
return { ...prevValue, currentStep: (prevValue.currentStep - 1) };
});
};
return (
<>
<div className="flex flex-col gap-1">
<Text fontSize={ 4 }>{ LocalizeText('help.emergency.chat_report.subtitle') }</Text>
<Text>{ LocalizeText('help.cfh.input.text') }</Text>
</div>
<textarea className="min-h-[calc(1.5em+ .5rem+2px)] px-[.5rem] py-[.25rem] rounded-[.2rem] h-full" value={ message } onChange={ event => setMessage(event.target.value) } />
<Flex gap={ 2 } justifyContent="between">
<Button disabled={ !(activeReport.reportType === ReportType.BULLY || activeReport.reportType === ReportType.EMERGENCY) } variant="secondary" onClick={ back }>
{ LocalizeText('generic.back') }
</Button>
<Button disabled={ (message.length < 15) } onClick={ submitMessage }>
{ LocalizeText('help.emergency.main.submit.button') }
</Button>
</Flex>
</>
);
};
@@ -0,0 +1,37 @@
import { GetCfhStatusMessageComposer } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { DispatchUiEvent, GetConfigurationValue, LocalizeText, ReportState, ReportType, SendMessageComposer } from '../../../api';
import { Button, Text } from '../../../common';
import { GuideToolEvent } from '../../../events';
import { useHelp } from '../../../hooks';
export const HelpIndexView: FC<{}> = props =>
{
const { setActiveReport = null } = useHelp();
const onReportClick = () =>
{
setActiveReport(prevValue =>
{
const currentStep = ReportState.SELECT_USER;
const reportType = ReportType.BULLY;
return { ...prevValue, currentStep, reportType };
});
};
return (
<>
<div className="flex flex-col justify-center alignp-items-enter !flex-grow gap-1">
<Text fontSize={ 3 }>{ LocalizeText('help.main.frame.title') }</Text>
<Text>{ LocalizeText('help.main.self.description') }</Text>
</div>
<div className="flex flex-col gap-1">
<Button onClick={ onReportClick }>{ LocalizeText('help.main.bully.subtitle') }</Button>
<Button disabled={ !GetConfigurationValue('guides.enabled') } onClick={ () => DispatchUiEvent(new GuideToolEvent(GuideToolEvent.CREATE_HELP_REQUEST)) }>{ LocalizeText('help.main.help.title') }</Button>
<Button disabled={ true }>{ LocalizeText('help.main.self.tips.title') }</Button>
</div>
<Button textColor="black" variant="link" onClick={ () => SendMessageComposer(new GetCfhStatusMessageComposer(false)) }>{ LocalizeText('help.main.my.sanction.status') }</Button>
</>
);
};
@@ -0,0 +1,57 @@
import { CallForHelpFromForumMessageMessageComposer, CallForHelpFromForumThreadMessageComposer, CallForHelpFromIMMessageComposer, CallForHelpFromPhotoMessageComposer, CallForHelpMessageComposer } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { LocalizeText, ReportType, SendMessageComposer } from '../../../api';
import { Button, Text } from '../../../common';
import { useHelp } from '../../../hooks';
export const ReportSummaryView: FC<{}> = props =>
{
const { activeReport = null, setActiveReport = null } = useHelp();
const submitReport = () =>
{
const chats: (string | number )[] = [];
switch(activeReport.reportType)
{
case ReportType.BULLY:
case ReportType.EMERGENCY:
case ReportType.ROOM: {
const reportedRoomId = ((activeReport.roomId <= 0) ? activeReport.reportedChats[0].roomId : activeReport.roomId);
activeReport.reportedChats.forEach(entry => chats.push(entry.webId, entry.message));
SendMessageComposer(new CallForHelpMessageComposer(activeReport.message, activeReport.cfhTopic, activeReport.reportedUserId, reportedRoomId, chats));
break;
}
case ReportType.IM:
activeReport.reportedChats.forEach(entry => chats.push(entry.webId, entry.message));
SendMessageComposer(new CallForHelpFromIMMessageComposer(activeReport.message, activeReport.cfhTopic, activeReport.reportedUserId, chats));
break;
case ReportType.THREAD:
SendMessageComposer(new CallForHelpFromForumThreadMessageComposer(activeReport.groupId, activeReport.threadId, activeReport.cfhTopic, activeReport.message));
break;
case ReportType.MESSAGE:
SendMessageComposer(new CallForHelpFromForumMessageMessageComposer(activeReport.groupId, activeReport.threadId, activeReport.messageId, activeReport.cfhTopic, activeReport.message));
break;
case ReportType.PHOTO:
SendMessageComposer(new CallForHelpFromPhotoMessageComposer(activeReport.extraData, activeReport.roomId, activeReport.reportedUserId, activeReport.cfhTopic, activeReport.roomObjectId));
break;
}
setActiveReport(null);
};
return (
<>
<div className="flex flex-col gap-1">
<Text fontSize={ 4 }>{ LocalizeText('help.cfh.button.send') }</Text>
<Text>{ LocalizeText('help.main.summary') }</Text>
</div>
<Button variant="success" onClick={ submitReport }>
{ LocalizeText('guide.help.request.emergency.submit.button') }
</Button>
</>
);
};
@@ -0,0 +1,75 @@
import { FC } from 'react';
import { LocalizeText } from '../../../api';
import { Button, Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../common';
import { useHelp } from '../../../hooks';
export const SanctionSatusView: FC<{}> = props =>
{
const { sanctionInfo = null, setSanctionInfo = null } = useHelp();
const sanctionLocalization = (param: string, sanctionName: string, length?: number) =>
{
let localizationName = `help.sanction.${ param }`;
switch(sanctionName)
{
case 'ALERT':
localizationName = (localizationName + '.alert');
break;
case 'MUTE':
localizationName = (localizationName + '.mute');
break;
case 'BAN_PERMANENT':
localizationName = (localizationName + '.permban');
break;
default:
localizationName = (localizationName + '.ban');
if(length > 24)
{
localizationName = (localizationName + '.days');
return LocalizeText(localizationName, [ 'days' ], [ (length / 24).toString() ]);
}
}
return LocalizeText(localizationName, [ 'hours' ], [ length.toString() ]);
};
if(!sanctionInfo) return null;
return (
<NitroCardView className="nitro-help" theme="primary-slim">
<NitroCardHeaderView headerText={ LocalizeText('help.sanction.info.title') } onCloseClick={ () => setSanctionInfo(null) } />
<NitroCardContentView className="text-black">
<Grid>
<Column center overflow="hidden" size={ 5 }>
<div className="index-image" />
</Column>
<Column justifyContent="between" overflow="hidden" size={ 7 }>
{ (sanctionInfo.sanctionReason === 'cfh.reason.EMPTY')
? <div className="col-span-12 font-bold ">{ LocalizeText('help.sanction.current.none') }</div>
: <>
{ ((sanctionInfo.probationHoursLeft > 0) || (sanctionInfo.isSanctionActive)) &&
<div className="col-span-12 font-bold ">{ LocalizeText('help.sanction.probation.reminder') }</div>
}
<div className={ `col-span-12 font-bold ${ sanctionInfo.isSanctionNew ? 'text-danger' : '' }` }>
{ LocalizeText('help.sanction.last.sanction') } { sanctionLocalization('current', sanctionInfo.sanctionName, sanctionInfo.sanctionLengthHours) }
</div>
<div className="col-span-12">{ LocalizeText('generic.start.time') } { sanctionInfo.sanctionCreationTime }</div>
<div className="col-span-12">{ LocalizeText('generic.reason') } { sanctionInfo.sanctionReason }</div>
<div className="col-span-12">{ LocalizeText('help.sanction.probation.days.left') } { Math.trunc((sanctionInfo.probationHoursLeft / 24)) + 1 }</div>
</>
}
{ ((sanctionInfo.hasCustomMute) && (!(sanctionInfo.isSanctionActive))) &&
<div className="col-span-12 font-bold ">{ LocalizeText('help.sanction.custom.mute') }</div>
}
{ (sanctionInfo.tradeLockExpiryTime && sanctionInfo.tradeLockExpiryTime.length > 0) &&
<div className="col-span-12 font-bold ">{ LocalizeText('trade.locked.until') } { sanctionInfo.tradeLockExpiryTime }</div>
}
<div className="col-span-12">{ sanctionLocalization('next', sanctionInfo.nextSanctionName, sanctionInfo.nextSanctionLengthHours) }</div>
<Button variant="success" onClick={ event => setSanctionInfo(null) }>{ LocalizeText('habbo.way.ok.button') }</Button>
</Column>
</Grid>
</NitroCardContentView>
</NitroCardView>
);
};
@@ -0,0 +1,90 @@
import { RoomObjectType } from '@nitrots/nitro-renderer';
import { FC, useMemo, useState } from 'react';
import { ChatEntryType, IChatEntry, LocalizeText, ReportState, ReportType } from '../../../api';
import { AutoGrid, Button, Column, Flex, LayoutGridItem, Text } from '../../../common';
import { useChatHistory, useHelp } from '../../../hooks';
export const SelectReportedChatsView: FC<{}> = props =>
{
const [ selectedChats, setSelectedChats ] = useState<IChatEntry[]>([]);
const { activeReport = null, setActiveReport = null } = useHelp();
const { chatHistory = [], messengerHistory = [] } = useChatHistory();
const userChats = useMemo(() =>
{
switch(activeReport.reportType)
{
case ReportType.BULLY:
case ReportType.EMERGENCY:
return chatHistory.filter(chat => (chat.type === ChatEntryType.TYPE_CHAT) && (chat.webId === activeReport.reportedUserId) && (chat.entityType === RoomObjectType.USER));
case ReportType.IM:
return messengerHistory.filter(chat => (chat.webId === activeReport.reportedUserId) && (chat.type === ChatEntryType.TYPE_IM));
}
return [];
}, [ activeReport, chatHistory, messengerHistory ]);
const selectChat = (chatEntry: IChatEntry) =>
{
setSelectedChats(prevValue =>
{
const newValue = [ ...prevValue ];
const index = newValue.indexOf(chatEntry);
if(index >= 0) newValue.splice(index, 1);
else newValue.push(chatEntry);
return newValue;
});
};
const submitChats = () =>
{
if(!selectedChats || (selectedChats.length <= 0)) return;
setActiveReport(prevValue =>
{
return { ...prevValue, reportedChats: selectedChats, currentStep: ReportState.SELECT_TOPICS };
});
};
const back = () =>
{
setActiveReport(prevValue =>
{
return { ...prevValue, currentStep: (prevValue.currentStep - 1) };
});
};
return (
<>
<div className="flex flex-col gap-1">
<Text fontSize={ 4 }>{ LocalizeText('help.emergency.chat_report.subtitle') }</Text>
<Text>{ LocalizeText('help.emergency.chat_report.description') }</Text>
</div>
<Column gap={ 1 } overflow="hidden">
{ !userChats || !userChats.length &&
<Text>{ LocalizeText('help.cfh.error.no_user_data') }</Text> }
{ (userChats.length > 0) &&
<AutoGrid columnCount={ 1 } columnMinHeight={ 25 } gap={ 1 } overflow="auto">
{ userChats.map((chat, index) =>
{
return (
<LayoutGridItem key={ chat.id } itemActive={ (selectedChats.indexOf(chat) >= 0) } onClick={ event => selectChat(chat) }>
<Text>{ chat.message }</Text>
</LayoutGridItem>
);
}) }
</AutoGrid> }
</Column>
<Flex gap={ 2 } justifyContent="between">
<Button disabled={ (activeReport.reportType === ReportType.IM) } variant="secondary" onClick={ back }>
{ LocalizeText('generic.back') }
</Button>
<Button disabled={ (selectedChats.length <= 0) } onClick={ submitChats }>
{ LocalizeText('help.emergency.main.submit.button') }
</Button>
</Flex>
</>
);
};
@@ -0,0 +1,85 @@
import { GetSessionDataManager, RoomObjectType } from '@nitrots/nitro-renderer';
import { FC, useMemo, useState } from 'react';
import { ChatEntryType, IReportedUser, LocalizeText, ReportState } from '../../../api';
import { AutoGrid, Button, Column, Flex, LayoutGridItem, Text } from '../../../common';
import { useChatHistory, useHelp } from '../../../hooks';
export const SelectReportedUserView: FC<{}> = props =>
{
const [ selectedUserId, setSelectedUserId ] = useState(-1);
const { chatHistory = [] } = useChatHistory();
const { activeReport = null, setActiveReport = null } = useHelp();
const availableUsers = useMemo(() =>
{
const users: Map<number, IReportedUser> = new Map();
chatHistory.forEach(chat =>
{
if((chat.type === ChatEntryType.TYPE_CHAT) && (chat.entityType === RoomObjectType.USER) && (chat.webId !== GetSessionDataManager().userId) && !users.has(chat.webId)) users.set(chat.webId, { id: chat.webId, username: chat.name });
});
return Array.from(users.values());
}, [ chatHistory ]);
const submitUser = (userId: number) =>
{
if(userId <= 0) return;
setActiveReport(prevValue =>
{
return { ...prevValue, reportedUserId: userId, currentStep: ReportState.SELECT_CHATS };
});
};
const selectUser = (userId: number) =>
{
setSelectedUserId(prevValue =>
{
if(userId === prevValue) return -1;
return userId;
});
};
const back = () =>
{
setActiveReport(prevValue =>
{
return { ...prevValue, currentStep: (prevValue.currentStep - 1) };
});
};
return (
<>
<div className="flex flex-col gap-1">
<Text fontSize={ 4 }>{ LocalizeText('help.emergency.main.step.two.title') }</Text>
{ (availableUsers.length > 0) &&
<Text>{ LocalizeText('report.user.pick.user') }</Text> }
</div>
<Column gap={ 1 } overflow="hidden">
{ !!!availableUsers.length &&
<Text>{ LocalizeText('report.user.error.nolist') }</Text> }
{ (availableUsers.length > 0) &&
<AutoGrid columnCount={ 1 } columnMinHeight={ 25 } gap={ 1 }>
{ availableUsers.map((user, index) =>
{
return (
<LayoutGridItem key={ user.id } itemActive={ (selectedUserId === user.id) } onClick={ event => selectUser(user.id) }>
<span dangerouslySetInnerHTML={ { __html: (user.username) } } />
</LayoutGridItem>
);
}) }
</AutoGrid> }
</Column>
<Flex gap={ 2 } justifyContent="between">
<Button variant="secondary" onClick={ back }>
{ LocalizeText('generic.back') }
</Button>
<Button disabled={ (selectedUserId <= 0) } onClick={ () => submitUser(selectedUserId) }>
{ LocalizeText('help.emergency.main.submit.button') }
</Button>
</Flex>
</>
);
};
@@ -0,0 +1,53 @@
import { FC, useState } from 'react';
import { LocalizeText, ReportState } from '../../../api';
import { Button, Column, Flex, Text } from '../../../common';
import { useHelp, useModTools } from '../../../hooks';
export const SelectTopicView: FC<{}> = props =>
{
const [ selectedCategory, setSelectedCategory ] = useState(-1);
const [ selectedTopic, setSelectedTopic ] = useState(-1);
const { setActiveReport = null } = useHelp();
const { cfhCategories = [] } = useModTools();
const submitTopic = () =>
{
if((selectedCategory < 0) || (selectedTopic < 0)) return;
setActiveReport(prevValue =>
{
return { ...prevValue, cfhCategory: selectedCategory, cfhTopic: cfhCategories[selectedCategory].topics[selectedTopic].id, currentStep: ReportState.INPUT_REPORT_MESSAGE };
});
};
const back = () =>
{
setActiveReport(prevValue =>
{
return { ...prevValue, currentStep: (prevValue.currentStep - 1) };
});
};
return (
<>
<div className="flex flex-col gap-1">
<Text fontSize={ 4 }>{ LocalizeText('help.emergency.chat_report.subtitle') }</Text>
<Text>{ LocalizeText('help.cfh.pick.topic') }</Text>
</div>
<Column gap={ 1 } overflow="auto">
{ (selectedCategory < 0) &&
cfhCategories.map((category, index) => <Button key={ index } variant="danger" onClick={ event => setSelectedCategory(index) }>{ LocalizeText(`help.cfh.reason.${ category.name }`) }</Button>) }
{ (selectedCategory >= 0) &&
cfhCategories[selectedCategory].topics.map((topic, index) => <Button key={ index } active={ (selectedTopic === index) } variant="danger" onClick={ event => setSelectedTopic(index) }>{ LocalizeText(`help.cfh.topic.${ topic.id }`) }</Button>) }
</Column>
<Flex gap={ 2 } justifyContent="between">
<Button variant="secondary" onClick={ back }>
{ LocalizeText('generic.back') }
</Button>
<Button disabled={ (selectedTopic < 0) } onClick={ submitTopic }>
{ LocalizeText('help.emergency.main.submit.button') }
</Button>
</Flex>
</>
);
};
@@ -0,0 +1,44 @@
import { ChangeUserNameMessageComposer, GetSessionDataManager, UserNameChangeMessageEvent } from '@nitrots/nitro-renderer';
import { FC, useState } from 'react';
import { LocalizeText, SendMessageComposer } from '../../../../api';
import { useMessageEvent } from '../../../../hooks';
import { NameChangeLayoutViewProps } from './NameChangeView.types';
export const NameChangeConfirmationView: FC<NameChangeLayoutViewProps> = props =>
{
const { username = '', onAction = null } = props;
const [ isConfirming, setIsConfirming ] = useState<boolean>(false);
const confirm = () =>
{
if(isConfirming) return;
setIsConfirming(true);
SendMessageComposer(new ChangeUserNameMessageComposer(username));
};
useMessageEvent<UserNameChangeMessageEvent>(UserNameChangeMessageEvent, event =>
{
const parser = event.getParser();
if(!parser) return;
if(parser.webId !== GetSessionDataManager().userId) return;
onAction('close');
});
return (
<div className="flex flex-col gap-4 h-full">
<div className="bg-muted rounded p-2 text-center">{ LocalizeText('tutorial.name_change.info.confirm') }</div>
<div className="flex flex-col items-center gap-1 h-full">
<div>{ LocalizeText('tutorial.name_change.confirm') }</div>
<div className="font-bold ">{ username }</div>
</div>
<div className="flex gap-2">
<button className="btn btn-success w-full" disabled={ isConfirming } onClick={ confirm }>{ LocalizeText('generic.ok') }</button>
<button className="btn btn-primary w-full" onClick={ () => onAction('close') }>{ LocalizeText('cancel') }</button>
</div>
</div>
);
};
@@ -0,0 +1,20 @@
import { GetSessionDataManager } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { LocalizeText } from '../../../../api';
import { NameChangeLayoutViewProps } from './NameChangeView.types';
export const NameChangeInitView: FC<NameChangeLayoutViewProps> = props =>
{
const { onAction = null } = props;
return (
<div className="flex flex-col gap-4 h-full">
<div className="bg-muted rounded p-2 text-center">{ LocalizeText('tutorial.name_change.info.main') }</div>
<div className="font-bold flex items-center justify-center size-full">{ LocalizeText('tutorial.name_change.current', [ 'name' ], [ GetSessionDataManager().userName ]) }</div>
<div className="flex gap-2">
<button className="btn btn-success w-full" onClick={ () => onAction('start') }>{ LocalizeText('tutorial.name_change.change') }</button>
<button className="btn btn-primary w-full" onClick={ () => onAction('confirmation', GetSessionDataManager().userName) }>{ LocalizeText('tutorial.name_change.keep') }</button>
</div>
</div>
);
};
@@ -0,0 +1,98 @@
import { CheckUserNameMessageComposer, CheckUserNameResultMessageEvent } from '@nitrots/nitro-renderer';
import { FC, useState } from 'react';
import { LocalizeText, SendMessageComposer } from '../../../../api';
import { useMessageEvent } from '../../../../hooks';
import { NitroInput } from '../../../../layout';
import { NameChangeLayoutViewProps } from './NameChangeView.types';
const AVAILABLE: number = 0;
const TOO_SHORT: number = 2;
const TOO_LONG: number = 3;
const NOT_VALID: number = 4;
const TAKEN_WITH_SUGGESTIONS: number = 5;
const DISABLED: number = 6;
export const NameChangeInputView: FC<NameChangeLayoutViewProps> = props =>
{
const { onAction = null } = props;
const [ newUsername, setNewUsername ] = useState<string>('');
const [ canProceed, setCanProceed ] = useState<boolean>(false);
const [ isChecking, setIsChecking ] = useState<boolean>(false);
const [ errorCode, setErrorCode ] = useState<string>(null);
const [ suggestions, setSuggestions ] = useState<string[]>([]);
const check = () =>
{
if(newUsername === '') return;
setCanProceed(false);
setSuggestions([]);
setErrorCode(null);
setIsChecking(true);
SendMessageComposer(new CheckUserNameMessageComposer(newUsername));
};
const handleUsernameChange = (username: string) =>
{
setCanProceed(false);
setSuggestions([]);
setErrorCode(null);
setNewUsername(username);
};
useMessageEvent<CheckUserNameResultMessageEvent>(CheckUserNameResultMessageEvent, event =>
{
setIsChecking(false);
const parser = event.getParser();
if(!parser) return;
switch(parser.resultCode)
{
case AVAILABLE:
setCanProceed(true);
break;
case TOO_SHORT:
setErrorCode('short');
break;
case TOO_LONG:
setErrorCode('long');
break;
case NOT_VALID:
setErrorCode('invalid');
break;
case TAKEN_WITH_SUGGESTIONS:
setSuggestions(parser.nameSuggestions);
setErrorCode('taken');
break;
case DISABLED:
setErrorCode('change_not_allowed');
}
});
return (
<div className="flex flex-col h-full gap-3">
<div>{ LocalizeText('tutorial.name_change.info.select') }</div>
<div className="flex gap-2">
<NitroInput type="text" value={ newUsername } onChange={ event => handleUsernameChange(event.target.value) } />
<button className="btn btn-primary" disabled={ newUsername === '' || isChecking } onClick={ check }>{ LocalizeText('tutorial.name_change.check') }</button>
</div>
{ !errorCode && !canProceed &&
<div className="p-2 text-center rounded bg-muted">{ LocalizeText('help.tutorial.name.info') }</div> }
{ errorCode &&
<div className="p-2 text-center text-white rounded bg-danger">{ LocalizeText(`help.tutorial.name.${ errorCode }`, [ 'name' ], [ newUsername ]) }</div> }
{ canProceed &&
<div className="p-2 text-center text-white rounded bg-success">{ LocalizeText('help.tutorial.name.available', [ 'name' ], [ newUsername ]) }</div> }
{ suggestions &&
<div className="flex flex-col gap-2">
{ suggestions.map((suggestion, index) => <div key={ index } className="p-1 rounded cursor-pointer col bg-muted" onClick={ () => handleUsernameChange(suggestion) }>{ suggestion }</div>) }
</div> }
<div className="flex gap-2">
<button className="w-full btn btn-success" disabled={ !canProceed } onClick={ () => onAction('confirmation', newUsername) }>{ LocalizeText('tutorial.name_change.pick') }</button>
<button className="w-full btn btn-primary" onClick={ () => onAction('close') }>{ LocalizeText('cancel') }</button>
</div>
</div>
);
};
@@ -0,0 +1,66 @@
import { FC, useMemo, useState } from 'react';
import { LocalizeText } from '../../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
import { HelpNameChangeEvent } from '../../../../events';
import { useUiEvent } from '../../../../hooks';
import { NameChangeConfirmationView } from './NameChangeConfirmationView';
import { NameChangeInitView } from './NameChangeInitView';
import { NameChangeInputView } from './NameChangeInputView';
const INIT: string = 'INIT';
const INPUT: string = 'INPUT';
const CONFIRMATION: string = 'CONFIRMATION';
export const NameChangeView:FC<{}> = props =>
{
const [ isVisible, setIsVisible ] = useState<boolean>(false);
const [ layout, setLayout ] = useState<string>(INIT);
const [ newUsername, setNewUsername ] = useState<string>('');
const onAction = (action: string, value?: string) =>
{
switch(action)
{
case 'start':
setLayout(INPUT);
break;
case 'confirmation':
setNewUsername(value);
setLayout(CONFIRMATION);
break;
case 'close':
setNewUsername('');
setIsVisible(false);
break;
}
};
const titleKey = useMemo(() =>
{
switch(layout)
{
case INIT: return 'tutorial.name_change.title.main';
case INPUT: return 'tutorial.name_change.title.select';
case CONFIRMATION: return 'tutorial.name_change.title.confirm';
}
}, [ layout ]);
useUiEvent<HelpNameChangeEvent>(HelpNameChangeEvent.INIT, event =>
{
setLayout(INIT);
setIsVisible(true);
});
if(!isVisible) return null;
return (
<NitroCardView className="nitro-change-username" theme="primary-slim">
<NitroCardHeaderView headerText={ LocalizeText(titleKey) } onCloseClick={ () => onAction('close') } />
<NitroCardContentView className="text-black">
{ layout === INIT && <NameChangeInitView onAction={ onAction } /> }
{ layout === INPUT && <NameChangeInputView onAction={ onAction } /> }
{ layout === CONFIRMATION && <NameChangeConfirmationView username={ newUsername } onAction={ onAction } /> }
</NitroCardContentView>
</NitroCardView>
);
};
@@ -0,0 +1,5 @@
export interface NameChangeLayoutViewProps
{
username?: string;
onAction: (action: string, value?: string) => void;
}