mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-20 15:36:18 +00:00
🆙 Init V3
This commit is contained in:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user