🆙 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,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;
}