mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
Merge remote-tracking branch 'upstream/main'
* upstream/main: feat(wired): update source-aware furni and signal UI wired ui: add source selector support
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { GetSessionDataManager } from '@nitrots/nitro-renderer';
|
||||
import { CSSProperties, FC, PropsWithChildren, useEffect, useState } from 'react';
|
||||
import { CSSProperties, FC, PropsWithChildren, ReactNode, useEffect, useState } from 'react';
|
||||
import { LocalizeText, WiredFurniType, WiredSelectionVisualizer } from '../../../api';
|
||||
import { Button, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../common';
|
||||
import { useWired } from '../../../hooks';
|
||||
@@ -13,11 +13,12 @@ export interface WiredBaseViewProps
|
||||
save: () => void;
|
||||
validate?: () => boolean;
|
||||
cardStyle?: CSSProperties;
|
||||
footer?: ReactNode;
|
||||
}
|
||||
|
||||
export const WiredBaseView: FC<PropsWithChildren<WiredBaseViewProps>> = props =>
|
||||
{
|
||||
const { wiredType = '', requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, children = null, hasSpecialInput = false, cardStyle = undefined } = props;
|
||||
const { wiredType = '', requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, children = null, hasSpecialInput = false, cardStyle = undefined, footer = null } = props;
|
||||
const [ wiredName, setWiredName ] = useState<string>(null);
|
||||
const [ wiredDescription, setWiredDescription ] = useState<string>(null);
|
||||
const [ needsSave, setNeedsSave ] = useState<boolean>(false);
|
||||
@@ -83,9 +84,14 @@ export const WiredBaseView: FC<PropsWithChildren<WiredBaseViewProps>> = props =>
|
||||
return [];
|
||||
});
|
||||
}
|
||||
}, [ trigger, hasSpecialInput, setIntParams, setStringParam, setFurniIds ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
|
||||
setAllowsFurni(requiresFurni);
|
||||
}, [ trigger, hasSpecialInput, requiresFurni, setIntParams, setStringParam, setFurniIds, setAllowsFurni ]);
|
||||
}, [ trigger, requiresFurni, setAllowsFurni ]);
|
||||
|
||||
return (
|
||||
<NitroCardView className="nitro-wired" theme="primary-slim" uniqueKey="nitro-wired" style={ cardStyle }>
|
||||
@@ -105,6 +111,11 @@ export const WiredBaseView: FC<PropsWithChildren<WiredBaseViewProps>> = props =>
|
||||
<hr className="m-0 bg-dark" />
|
||||
<WiredFurniSelectorView />
|
||||
</> }
|
||||
{ footer &&
|
||||
<>
|
||||
<hr className="m-0 bg-dark" />
|
||||
{ footer }
|
||||
</> }
|
||||
<div className="flex items-center gap-1">
|
||||
<Button fullWidth variant="success" onClick={ onSave }>{ LocalizeText('wiredfurni.ready') }</Button>
|
||||
<Button fullWidth variant="secondary" onClick={ onClose }>{ LocalizeText('cancel') }</Button>
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import { FC } from 'react';
|
||||
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa';
|
||||
import { LocalizeText } from '../../../api';
|
||||
import { Button, Text } from '../../../common';
|
||||
|
||||
export const FURNI_SOURCES = [
|
||||
{ value: 0, label: 'wiredfurni.params.sources.furni.0' },
|
||||
{ value: 100, label: 'wiredfurni.params.sources.furni.100' },
|
||||
{ value: 200, label: 'wiredfurni.params.sources.furni.200' },
|
||||
{ value: 201, label: 'wiredfurni.params.sources.furni.201' }
|
||||
];
|
||||
|
||||
export const USER_SOURCES = [
|
||||
{ value: 0, label: 'wiredfurni.params.sources.users.0' },
|
||||
{ value: 200, label: 'wiredfurni.params.sources.users.200' },
|
||||
{ value: 201, label: 'wiredfurni.params.sources.users.201' }
|
||||
];
|
||||
|
||||
interface WiredSourcesSelectorProps
|
||||
{
|
||||
showFurni?: boolean;
|
||||
showUsers?: boolean;
|
||||
furniSource?: number;
|
||||
userSource?: number;
|
||||
onChangeFurni?: (source: number) => void;
|
||||
onChangeUsers?: (source: number) => void;
|
||||
}
|
||||
|
||||
export const WiredSourcesSelector: FC<WiredSourcesSelectorProps> = props =>
|
||||
{
|
||||
const { showFurni = false, showUsers = false, furniSource = 0, userSource = 0, onChangeFurni = null, onChangeUsers = null } = props;
|
||||
|
||||
const furniIndex = Math.max(0, FURNI_SOURCES.findIndex(s => s.value === furniSource));
|
||||
const userIndex = Math.max(0, USER_SOURCES.findIndex(s => s.value === userSource));
|
||||
|
||||
const prevFurni = () =>
|
||||
{
|
||||
const next = (furniIndex - 1 + FURNI_SOURCES.length) % FURNI_SOURCES.length;
|
||||
onChangeFurni && onChangeFurni(FURNI_SOURCES[next].value);
|
||||
};
|
||||
|
||||
const nextFurni = () =>
|
||||
{
|
||||
const next = (furniIndex + 1) % FURNI_SOURCES.length;
|
||||
onChangeFurni && onChangeFurni(FURNI_SOURCES[next].value);
|
||||
};
|
||||
|
||||
const prevUsers = () =>
|
||||
{
|
||||
const next = (userIndex - 1 + USER_SOURCES.length) % USER_SOURCES.length;
|
||||
onChangeUsers && onChangeUsers(USER_SOURCES[next].value);
|
||||
};
|
||||
|
||||
const nextUsers = () =>
|
||||
{
|
||||
const next = (userIndex + 1) % USER_SOURCES.length;
|
||||
onChangeUsers && onChangeUsers(USER_SOURCES[next].value);
|
||||
};
|
||||
|
||||
if(!showFurni && !showUsers) return null;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
{ showFurni &&
|
||||
<>
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.sources.furni.title') }</Text>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="primary" className="px-2 py-1" onClick={ prevFurni }><FaChevronLeft /></Button>
|
||||
<div className="flex flex-1 items-center justify-center">
|
||||
<Text small>{ LocalizeText(FURNI_SOURCES[furniIndex].label) }</Text>
|
||||
</div>
|
||||
<Button variant="primary" className="px-2 py-1" onClick={ nextFurni }><FaChevronRight /></Button>
|
||||
</div>
|
||||
</> }
|
||||
|
||||
{ showFurni && showUsers && <hr className="m-0 bg-dark" /> }
|
||||
|
||||
{ showUsers &&
|
||||
<>
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.sources.users.title') }</Text>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="primary" className="px-2 py-1" onClick={ prevUsers }><FaChevronLeft /></Button>
|
||||
<div className="flex flex-1 items-center justify-center">
|
||||
<Text small>{ LocalizeText(USER_SOURCES[userIndex].label) }</Text>
|
||||
</div>
|
||||
<Button variant="primary" className="px-2 py-1" onClick={ nextUsers }><FaChevronRight /></Button>
|
||||
</div>
|
||||
</> }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { WiredActionDefinition } from '@nitrots/nitro-renderer';
|
||||
import { CSSProperties, FC, PropsWithChildren, useEffect } from 'react';
|
||||
import { CSSProperties, FC, PropsWithChildren, ReactNode, useEffect } from 'react';
|
||||
import { GetWiredTimeLocale, LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Slider, Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
@@ -13,11 +13,12 @@ export interface WiredActionBaseViewProps
|
||||
validate?: () => boolean;
|
||||
cardStyle?: CSSProperties;
|
||||
hideDelay?: boolean;
|
||||
footer?: ReactNode;
|
||||
}
|
||||
|
||||
export const WiredActionBaseView: FC<PropsWithChildren<WiredActionBaseViewProps>> = props =>
|
||||
{
|
||||
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, hasSpecialInput = false, children = null, cardStyle = undefined, hideDelay = false } = props;
|
||||
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, hasSpecialInput = false, children = null, cardStyle = undefined, hideDelay = false, footer = null } = props;
|
||||
const { trigger = null, actionDelay = 0, setActionDelay = null } = useWired();
|
||||
|
||||
useEffect(() =>
|
||||
@@ -26,7 +27,7 @@ export const WiredActionBaseView: FC<PropsWithChildren<WiredActionBaseViewProps>
|
||||
}, [ trigger, setActionDelay ]);
|
||||
|
||||
return (
|
||||
<WiredBaseView hasSpecialInput={ hasSpecialInput } requiresFurni={ requiresFurni } save={ save } validate={ validate } wiredType="action" cardStyle={ cardStyle }>
|
||||
<WiredBaseView hasSpecialInput={ hasSpecialInput } requiresFurni={ requiresFurni } save={ save } validate={ validate } wiredType="action" cardStyle={ cardStyle } footer={ footer }>
|
||||
{ children }
|
||||
{ !hideDelay && !!children && <hr className="m-0 bg-dark" /> }
|
||||
{ !hideDelay && <div className="flex flex-col">
|
||||
|
||||
@@ -4,27 +4,38 @@ import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { NitroInput } from '../../../../layout';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionBotFollowAvatarView: FC<{}> = props =>
|
||||
{
|
||||
const [ botName, setBotName ] = useState('');
|
||||
const [ followMode, setFollowMode ] = useState(-1);
|
||||
const { trigger = null, setStringParam = null, setIntParams = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 1) return trigger.intData[1];
|
||||
return 0;
|
||||
});
|
||||
|
||||
const save = () =>
|
||||
{
|
||||
setStringParam(botName);
|
||||
setIntParams([ followMode ]);
|
||||
setIntParams([ followMode, userSource ]);
|
||||
};
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setBotName(trigger.stringData);
|
||||
setFollowMode((trigger.intData.length > 0) ? trigger.intData[0] : 0);
|
||||
setUserSource((trigger.intData.length > 1) ? trigger.intData[1] : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text>
|
||||
<NitroInput maxLength={ 32 } type="text" value={ botName } onChange={ event => setBotName(event.target.value) } />
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { NitroInput } from '../../../../layout';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
const ALLOWED_HAND_ITEM_IDS: number[] = [ 2, 5, 7, 8, 9, 10, 27 ];
|
||||
|
||||
@@ -12,21 +13,31 @@ export const WiredActionBotGiveHandItemView: FC<{}> = props =>
|
||||
const [ botName, setBotName ] = useState('');
|
||||
const [ handItemId, setHandItemId ] = useState(-1);
|
||||
const { trigger = null, setStringParam = null, setIntParams = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 1) return trigger.intData[1];
|
||||
return 0;
|
||||
});
|
||||
|
||||
const save = () =>
|
||||
{
|
||||
setStringParam(botName);
|
||||
setIntParams([ handItemId ]);
|
||||
setIntParams([ handItemId, userSource ]);
|
||||
};
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setBotName(trigger.stringData);
|
||||
setHandItemId((trigger.intData.length > 0) ? trigger.intData[0] : 0);
|
||||
setUserSource((trigger.intData.length > 1) ? trigger.intData[1] : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text>
|
||||
<NitroInput maxLength={ 32 } type="text" value={ botName } onChange={ event => setBotName(event.target.value) } />
|
||||
|
||||
@@ -4,21 +4,45 @@ import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { NitroInput } from '../../../../layout';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionBotMoveView: FC<{}> = props =>
|
||||
{
|
||||
const [ botName, setBotName ] = useState('');
|
||||
const { trigger = null, setStringParam = null } = useWired();
|
||||
const { trigger = null, setStringParam = null, setIntParams = null } = useWired();
|
||||
|
||||
const save = () => setStringParam(botName);
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 1) return trigger.intData[0];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
const save = () =>
|
||||
{
|
||||
setStringParam(botName);
|
||||
setIntParams([ furniSource ]);
|
||||
};
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
|
||||
setBotName(trigger.stringData);
|
||||
|
||||
if(trigger.intData.length >= 1) setFurniSource(trigger.intData[0]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID;
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text>
|
||||
<NitroInput maxLength={ 32 } type="text" value={ botName } onChange={ event => setBotName(event.target.value) } />
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { NitroInput } from '../../../../layout';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionBotTalkToAvatarView: FC<{}> = props =>
|
||||
{
|
||||
@@ -11,11 +12,16 @@ export const WiredActionBotTalkToAvatarView: FC<{}> = props =>
|
||||
const [ message, setMessage ] = useState('');
|
||||
const [ talkMode, setTalkMode ] = useState(-1);
|
||||
const { trigger = null, setStringParam = null, setIntParams = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 1) return trigger.intData[1];
|
||||
return 0;
|
||||
});
|
||||
|
||||
const save = () =>
|
||||
{
|
||||
setStringParam(botName + WIRED_STRING_DELIMETER + message);
|
||||
setIntParams([ talkMode ]);
|
||||
setIntParams([ talkMode, userSource ]);
|
||||
};
|
||||
|
||||
useEffect(() =>
|
||||
@@ -26,10 +32,15 @@ export const WiredActionBotTalkToAvatarView: FC<{}> = props =>
|
||||
if(data.length > 1) setMessage(data[1].length > 0 ? data[1] : '');
|
||||
|
||||
setTalkMode((trigger.intData.length > 0) ? trigger.intData[0] : 0);
|
||||
setUserSource((trigger.intData.length > 1) ? trigger.intData[1] : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text>
|
||||
<NitroInput maxLength={ 32 } type="text" value={ botName } onChange={ event => setBotName(event.target.value) } />
|
||||
|
||||
@@ -4,21 +4,45 @@ import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { NitroInput } from '../../../../layout';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionBotTeleportView: FC<{}> = props =>
|
||||
{
|
||||
const [ botName, setBotName ] = useState('');
|
||||
const { trigger = null, setStringParam = null } = useWired();
|
||||
const { trigger = null, setStringParam = null, setIntParams = null } = useWired();
|
||||
|
||||
const save = () => setStringParam(botName);
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 1) return trigger.intData[0];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
const save = () =>
|
||||
{
|
||||
setStringParam(botName);
|
||||
setIntParams([ furniSource ]);
|
||||
};
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
|
||||
setBotName(trigger.stringData);
|
||||
|
||||
if(trigger.intData.length >= 1) setFurniSource(trigger.intData[0]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID;
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text>
|
||||
<NitroInput maxLength={ 32 } type="text" value={ botName } onChange={ event => setBotName(event.target.value) } />
|
||||
|
||||
@@ -1,8 +1,37 @@
|
||||
import { FC } from 'react';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { WiredFurniType } from '../../../../api';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionCallAnotherStackView: FC<{}> = props =>
|
||||
{
|
||||
return <WiredActionBaseView hasSpecialInput={ false } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />;
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 1) return trigger.intData[0];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
|
||||
if(trigger.intData.length >= 1) setFurniSource(trigger.intData[0]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const save = () => setIntParams([ furniSource ]);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT;
|
||||
|
||||
return (
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> } />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,37 @@
|
||||
import { FC } from 'react';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { WiredFurniType } from '../../../../api';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionChaseView: FC<{}> = props =>
|
||||
{
|
||||
return <WiredActionBaseView hasSpecialInput={ false } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />;
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 1) return trigger.intData[0];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
|
||||
if(trigger.intData.length >= 1) setFurniSource(trigger.intData[0]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const save = () => setIntParams([ furniSource ]);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT;
|
||||
|
||||
return (
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> } />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,21 +4,37 @@ import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { NitroInput } from '../../../../layout';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionChatView: FC<{}> = props =>
|
||||
{
|
||||
const [ message, setMessage ] = useState('');
|
||||
const { trigger = null, setStringParam = null } = useWired();
|
||||
const { trigger = null, setStringParam = null, setIntParams = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 1) return trigger.intData[0];
|
||||
return 0;
|
||||
});
|
||||
|
||||
const save = () => setStringParam(message);
|
||||
const save = () =>
|
||||
{
|
||||
setStringParam(message);
|
||||
setIntParams([ userSource ]);
|
||||
};
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setMessage(trigger.stringData);
|
||||
if(trigger.intData.length >= 1) setUserSource(trigger.intData[0]);
|
||||
else setUserSource(0);
|
||||
}, [ trigger ]);
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.message') }</Text>
|
||||
<NitroInput maxLength={ GetConfigurationValue<number>('wired.action.chat.max.length', 100) } type="text" value={ message } onChange={ event => setMessage(event.target.value) } />
|
||||
|
||||
@@ -1,8 +1,37 @@
|
||||
import { FC } from 'react';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { WiredFurniType } from '../../../../api';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionFleeView: FC<{}> = props =>
|
||||
{
|
||||
return <WiredActionBaseView hasSpecialInput={ false } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />;
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 1) return trigger.intData[0];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
|
||||
if(trigger.intData.length >= 1) setFurniSource(trigger.intData[0]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const save = () => setIntParams([ furniSource ]);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT;
|
||||
|
||||
return (
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> } />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Button, Slider, Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { NitroInput } from '../../../../layout';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionGiveRewardView: FC<{}> = props =>
|
||||
{
|
||||
@@ -15,6 +16,11 @@ export const WiredActionGiveRewardView: FC<{}> = props =>
|
||||
const [ limitationInterval, setLimitationInterval ] = useState(1);
|
||||
const [ rewards, setRewards ] = useState<{ isBadge: boolean, itemCode: string, probability: number }[]>([]);
|
||||
const { trigger = null, setIntParams = null, setStringParam = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 4) return trigger.intData[4];
|
||||
return 0;
|
||||
});
|
||||
|
||||
const addReward = () => setRewards(rewards => [ ...rewards, { isBadge: false, itemCode: '', probability: null } ]);
|
||||
|
||||
@@ -59,7 +65,7 @@ export const WiredActionGiveRewardView: FC<{}> = props =>
|
||||
if(stringRewards.length > 0)
|
||||
{
|
||||
setStringParam(stringRewards.join(';'));
|
||||
setIntParams([ rewardTime, uniqueRewards ? 1 : 0, rewardsLimit, limitationInterval ]);
|
||||
setIntParams([ rewardTime, uniqueRewards ? 1 : 0, rewardsLimit, limitationInterval, userSource ]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -88,11 +94,16 @@ export const WiredActionGiveRewardView: FC<{}> = props =>
|
||||
setRewardsLimit((trigger.intData.length > 2) ? trigger.intData[2] : 0);
|
||||
setLimitationInterval((trigger.intData.length > 3) ? trigger.intData[3] : 0);
|
||||
setLimitEnabled((trigger.intData.length > 3) ? trigger.intData[3] > 0 : false);
|
||||
setUserSource((trigger.intData.length > 4) ? trigger.intData[4] : 0);
|
||||
setRewards(readRewards);
|
||||
}, [ trigger ]);
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> }>
|
||||
<div className="flex items-center gap-1">
|
||||
<input className="form-check-input" id="limitEnabled" type="checkbox" onChange={ event => setLimitEnabled(event.target.checked) } />
|
||||
<Text>{ LocalizeText('wiredfurni.params.prizelimit', [ 'amount' ], [ limitEnabled ? rewardsLimit.toString() : '' ]) }</Text>
|
||||
|
||||
@@ -3,14 +3,20 @@ import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Slider, Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionGiveScoreView: FC<{}> = props =>
|
||||
{
|
||||
const [ points, setPoints ] = useState(1);
|
||||
const [ time, setTime ] = useState(1);
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 2) return trigger.intData[2];
|
||||
return 0;
|
||||
});
|
||||
|
||||
const save = () => setIntParams([ points, time ]);
|
||||
const save = () => setIntParams([ points, time, userSource ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
@@ -24,10 +30,16 @@ export const WiredActionGiveScoreView: FC<{}> = props =>
|
||||
setPoints(1);
|
||||
setTime(1);
|
||||
}
|
||||
|
||||
setUserSource((trigger.intData.length > 2) ? trigger.intData[2] : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.setpoints', [ 'points' ], [ points.toString() ]) }</Text>
|
||||
<Slider
|
||||
|
||||
@@ -3,21 +3,32 @@ import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionJoinTeamView: FC<{}> = props =>
|
||||
{
|
||||
const [ selectedTeam, setSelectedTeam ] = useState(-1);
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 1) return trigger.intData[1];
|
||||
return 0;
|
||||
});
|
||||
|
||||
const save = () => setIntParams([ selectedTeam ]);
|
||||
const save = () => setIntParams([ selectedTeam, userSource ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setSelectedTeam((trigger.intData.length > 0) ? trigger.intData[0] : 0);
|
||||
setUserSource((trigger.intData.length > 1) ? trigger.intData[1] : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.team') }</Text>
|
||||
{ [ 1, 2, 3, 4 ].map(team =>
|
||||
|
||||
@@ -4,21 +4,37 @@ import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { NitroInput } from '../../../../layout';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionKickFromRoomView: FC<{}> = props =>
|
||||
{
|
||||
const [ message, setMessage ] = useState('');
|
||||
const { trigger = null, setStringParam = null } = useWired();
|
||||
const { trigger = null, setStringParam = null, setIntParams = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 1) return trigger.intData[0];
|
||||
return 0;
|
||||
});
|
||||
|
||||
const save = () => setStringParam(message);
|
||||
const save = () =>
|
||||
{
|
||||
setStringParam(message);
|
||||
setIntParams([ userSource ]);
|
||||
};
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setMessage(trigger.stringData);
|
||||
if(trigger.intData.length >= 1) setUserSource(trigger.intData[0]);
|
||||
else setUserSource(0);
|
||||
}, [ trigger ]);
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.message') }</Text>
|
||||
<NitroInput maxLength={ GetConfigurationValue<number>('wired.action.kick.from.room.max.length', 100) } type="text" value={ message } onChange={ event => setMessage(event.target.value) } />
|
||||
|
||||
@@ -1,8 +1,32 @@
|
||||
import { FC } from 'react';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { WiredFurniType } from '../../../../api';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionLeaveTeamView: FC<{}> = props =>
|
||||
{
|
||||
return <WiredActionBaseView hasSpecialInput={ false } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null } />;
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 1) return trigger.intData[0];
|
||||
return 0;
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
if(trigger.intData.length >= 1) setUserSource(trigger.intData[0]);
|
||||
else setUserSource(0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const save = () => setIntParams([ userSource ]);
|
||||
|
||||
return (
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> } />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
const directionOptions: { value: number, icon: string }[] = [
|
||||
{
|
||||
@@ -30,8 +31,13 @@ export const WiredActionMoveAndRotateFurniView: FC<{}> = props =>
|
||||
const [ movement, setMovement ] = useState(-1);
|
||||
const [ rotation, setRotation ] = useState(-1);
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 2) return trigger.intData[2];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
const save = () => setIntParams([ movement, rotation ]);
|
||||
const save = () => setIntParams([ movement, rotation, furniSource ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
@@ -45,10 +51,21 @@ export const WiredActionMoveAndRotateFurniView: FC<{}> = props =>
|
||||
setMovement(-1);
|
||||
setRotation(-1);
|
||||
}
|
||||
|
||||
if(trigger.intData.length > 2) setFurniSource(trigger.intData[2]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT;
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.startdir') }</Text>
|
||||
<div className="flex gap-1">
|
||||
|
||||
@@ -3,6 +3,7 @@ import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Slider, Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
const directionOptions: { value: number, icon: string }[] = [
|
||||
{
|
||||
@@ -28,8 +29,13 @@ export const WiredActionMoveFurniToView: FC<{}> = props =>
|
||||
const [ spacing, setSpacing ] = useState(-1);
|
||||
const [ movement, setMovement ] = useState(-1);
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 2) return trigger.intData[2];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
const save = () => setIntParams([ movement, spacing ]);
|
||||
const save = () => setIntParams([ movement, spacing, furniSource ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
@@ -43,10 +49,21 @@ export const WiredActionMoveFurniToView: FC<{}> = props =>
|
||||
setSpacing(-1);
|
||||
setMovement(-1);
|
||||
}
|
||||
|
||||
if(trigger.intData.length > 2) setFurniSource(trigger.intData[2]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE;
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.emptytiles', [ 'tiles' ], [ spacing.toString() ]) }</Text>
|
||||
<Slider
|
||||
|
||||
@@ -3,6 +3,7 @@ import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
const directionOptions: { value: number, icon: string }[] = [
|
||||
{
|
||||
@@ -42,8 +43,13 @@ export const WiredActionMoveFurniView: FC<{}> = props =>
|
||||
const [ movement, setMovement ] = useState(-1);
|
||||
const [ rotation, setRotation ] = useState(-1);
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 2) return trigger.intData[2];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
const save = () => setIntParams([ movement, rotation ]);
|
||||
const save = () => setIntParams([ movement, rotation, furniSource ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
@@ -57,10 +63,21 @@ export const WiredActionMoveFurniView: FC<{}> = props =>
|
||||
setMovement(-1);
|
||||
setRotation(-1);
|
||||
}
|
||||
|
||||
if(trigger.intData.length > 2) setFurniSource(trigger.intData[2]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT;
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.movefurni') }</Text>
|
||||
<div className="flex items-center gap-1">
|
||||
|
||||
@@ -4,27 +4,38 @@ import { Slider, Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { NitroInput } from '../../../../layout';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionMuteUserView: FC<{}> = props =>
|
||||
{
|
||||
const [ time, setTime ] = useState(-1);
|
||||
const [ message, setMessage ] = useState('');
|
||||
const { trigger = null, setIntParams = null, setStringParam = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 1) return trigger.intData[1];
|
||||
return 0;
|
||||
});
|
||||
|
||||
const save = () =>
|
||||
{
|
||||
setIntParams([ time ]);
|
||||
setIntParams([ time, userSource ]);
|
||||
setStringParam(message);
|
||||
};
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setTime((trigger.intData.length > 0) ? trigger.intData[0] : 0);
|
||||
setUserSource((trigger.intData.length > 1) ? trigger.intData[1] : 0);
|
||||
setMessage(trigger.stringData);
|
||||
}, [ trigger ]);
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.length.minutes', [ 'minutes' ], [ time.toString() ]) }</Text>
|
||||
<Slider
|
||||
|
||||
@@ -1,185 +1,213 @@
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Text } from '../../../../common';
|
||||
import { LocalizeText, WiredFurniType, WiredSelectionVisualizer } from '../../../../api';
|
||||
import { Button, Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
|
||||
const ANTENNA_PICKED = 0;
|
||||
const ANTENNA_TRIGGER = 1;
|
||||
const ANTENNA_INTERACTION_TYPES = [ 'antenna' ];
|
||||
|
||||
const FORWARD_NONE = 0;
|
||||
const FORWARD_TRIGGER = 1;
|
||||
const FORWARD_SELECTOR = 200;
|
||||
const FORWARD_SIGNAL = 201;
|
||||
const SOURCE_TRIGGER = 0;
|
||||
const SOURCE_SELECTED = 100;
|
||||
|
||||
const FURNI_FORWARD_OPTIONS = [
|
||||
{ value: FORWARD_TRIGGER, label: 'wiredfurni.params.sources.furni.0' },
|
||||
{ value: FORWARD_SELECTOR, label: 'wiredfurni.params.sources.furni.200' },
|
||||
{ value: FORWARD_SIGNAL, label: 'wiredfurni.params.sources.furni.201' },
|
||||
];
|
||||
const FORWARD_ITEM_DELIMITER = ';';
|
||||
|
||||
const USER_FORWARD_OPTIONS = [
|
||||
{ value: FORWARD_TRIGGER, label: 'wiredfurni.params.sources.users.0' },
|
||||
{ value: FORWARD_SELECTOR, label: 'wiredfurni.params.sources.users.200' },
|
||||
{ value: FORWARD_SIGNAL, label: 'wiredfurni.params.sources.users.201' },
|
||||
];
|
||||
type SelectionMode = 'antenna' | 'furni';
|
||||
|
||||
const parseForwardIds = (data: string): number[] =>
|
||||
{
|
||||
if(!data || !data.length) return [];
|
||||
|
||||
const ids = new Set<number>();
|
||||
|
||||
for(const part of data.split(/[;,\t]/))
|
||||
{
|
||||
const trimmed = part.trim();
|
||||
if(!trimmed.length) continue;
|
||||
|
||||
const value = parseInt(trimmed, 10);
|
||||
if(!isNaN(value) && value > 0) ids.add(value);
|
||||
}
|
||||
|
||||
return Array.from(ids);
|
||||
};
|
||||
|
||||
const serializeForwardIds = (ids: number[]): string =>
|
||||
{
|
||||
if(!ids || !ids.length) return '';
|
||||
|
||||
return ids.filter(id => (id > 0)).join(FORWARD_ITEM_DELIMITER);
|
||||
};
|
||||
|
||||
export const WiredActionSendSignalView: FC<{}> = () =>
|
||||
{
|
||||
const [ antennaSource, setAntennaSource ] = useState(ANTENNA_PICKED);
|
||||
const [ furniForward, setFurniForward ] = useState(FORWARD_NONE);
|
||||
const [ userForward, setUserForward ] = useState(FORWARD_NONE);
|
||||
const [ furniSource, setFurniSource ] = useState<number>(SOURCE_TRIGGER);
|
||||
const [ userSource, setUserSource ] = useState<number>(SOURCE_TRIGGER);
|
||||
const [ signalPerFurni, setSignalPerFurni ] = useState(false);
|
||||
const [ signalPerUser, setSignalPerUser ] = useState(false);
|
||||
const [ showAdvanced, setShowAdvanced ] = useState(false);
|
||||
const [ antennaIds, setAntennaIds ] = useState<number[]>([]);
|
||||
const [ forwardFurniIds, setForwardFurniIds ] = useState<number[]>([]);
|
||||
const [ selectionMode, setSelectionMode ] = useState<SelectionMode>('antenna');
|
||||
|
||||
const { trigger = null, setIntParams } = useWired();
|
||||
const { trigger = null, furniIds = [], setFurniIds = null, setIntParams = null, setStringParam = null, setAllowedInteractionTypes = null } = useWired();
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
|
||||
const p = trigger.intData;
|
||||
if(p.length >= 1) setAntennaSource(p[0]);
|
||||
if(p.length >= 2) setFurniForward(p[1]);
|
||||
if(p.length >= 3) setUserForward(p[2]);
|
||||
if(p.length >= 4) setSignalPerFurni(p[3] === 1);
|
||||
if(p.length >= 5) setSignalPerUser(p[4] === 1);
|
||||
if(p.length > 1) setFurniSource(p[1]);
|
||||
else setFurniSource(SOURCE_TRIGGER);
|
||||
|
||||
if(p.length >= 1 && (p[0] !== ANTENNA_PICKED || p[1] !== FORWARD_NONE ||
|
||||
p[2] !== FORWARD_NONE || (p.length >= 4 && p[3] === 1) || (p.length >= 5 && p[4] === 1)))
|
||||
{
|
||||
setShowAdvanced(true);
|
||||
}
|
||||
if(p.length > 2) setUserSource(p[2]);
|
||||
else setUserSource(SOURCE_TRIGGER);
|
||||
|
||||
setSignalPerFurni(p.length > 3 && p[3] === 1);
|
||||
setSignalPerUser(p.length > 4 && p[4] === 1);
|
||||
|
||||
setAntennaIds(trigger.selectedItems ?? []);
|
||||
setForwardFurniIds(parseForwardIds(trigger.stringData));
|
||||
setSelectionMode('antenna');
|
||||
}, [ trigger ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(selectionMode === 'antenna') setAllowedInteractionTypes(ANTENNA_INTERACTION_TYPES);
|
||||
else setAllowedInteractionTypes(null);
|
||||
|
||||
return () => setAllowedInteractionTypes(null);
|
||||
}, [ selectionMode, setAllowedInteractionTypes ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(selectionMode === 'antenna') setAntennaIds(furniIds);
|
||||
else setForwardFurniIds(furniIds);
|
||||
}, [ furniIds, selectionMode ]);
|
||||
|
||||
const applySelection = useCallback((nextIds: number[]) =>
|
||||
{
|
||||
if(!setFurniIds) return;
|
||||
|
||||
setFurniIds(prev =>
|
||||
{
|
||||
if(prev && prev.length) WiredSelectionVisualizer.clearSelectionShaderFromFurni(prev);
|
||||
if(nextIds && nextIds.length) WiredSelectionVisualizer.applySelectionShaderToFurni(nextIds);
|
||||
|
||||
return [ ...nextIds ];
|
||||
});
|
||||
}, [ setFurniIds ]);
|
||||
|
||||
const switchSelection = useCallback((mode: SelectionMode) =>
|
||||
{
|
||||
if(mode === selectionMode) return;
|
||||
if(mode === 'furni' && furniSource !== SOURCE_SELECTED) return;
|
||||
|
||||
const nextIds = (mode === 'antenna') ? antennaIds : forwardFurniIds;
|
||||
applySelection(nextIds);
|
||||
setSelectionMode(mode);
|
||||
}, [ selectionMode, furniSource, antennaIds, forwardFurniIds, applySelection ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) =>
|
||||
{
|
||||
if(forwardFurniIds.length) setForwardFurniIds([]);
|
||||
|
||||
if(selectionMode === 'furni')
|
||||
{
|
||||
applySelection(antennaIds);
|
||||
setSelectionMode('antenna');
|
||||
}
|
||||
|
||||
setFurniSource(next);
|
||||
};
|
||||
|
||||
const save = useCallback(() =>
|
||||
{
|
||||
if(selectionMode === 'furni')
|
||||
{
|
||||
setSelectionMode('antenna');
|
||||
applySelection(antennaIds);
|
||||
}
|
||||
|
||||
const antennaSource = (antennaIds && antennaIds.length) ? antennaIds[0] : 0;
|
||||
|
||||
setIntParams([
|
||||
antennaSource,
|
||||
furniForward,
|
||||
userForward,
|
||||
furniSource,
|
||||
userSource,
|
||||
signalPerFurni ? 1 : 0,
|
||||
signalPerUser ? 1 : 0,
|
||||
0,
|
||||
]);
|
||||
}, [ antennaSource, furniForward, userForward, signalPerFurni, signalPerUser, setIntParams ]);
|
||||
|
||||
setStringParam(serializeForwardIds(forwardFurniIds));
|
||||
}, [ selectionMode, antennaIds, furniSource, userSource, signalPerFurni, signalPerUser, forwardFurniIds, setIntParams, setStringParam, applySelection, setSelectionMode ]);
|
||||
|
||||
const selectionLimit = trigger?.maximumItemSelectionCount ?? 0;
|
||||
const forwardSelectionEnabled = (furniSource === SOURCE_SELECTED);
|
||||
|
||||
return (
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID }
|
||||
cardStyle={ { width: '400px' } }
|
||||
save={ save }>
|
||||
<div className="flex flex-col gap-2">
|
||||
|
||||
<div
|
||||
className="cursor-pointer text-center"
|
||||
onClick={ () => setShowAdvanced(!showAdvanced) }>
|
||||
<Text small underline>
|
||||
{ showAdvanced
|
||||
? LocalizeText('wiredfurni.params.hide_advanced')
|
||||
: LocalizeText('wiredfurni.params.show_advanced') }
|
||||
</Text>
|
||||
cardStyle={ { width: '400px' } }
|
||||
save={ save }
|
||||
footer={ (
|
||||
<WiredSourcesSelector
|
||||
showFurni={ true }
|
||||
showUsers={ true }
|
||||
furniSource={ furniSource }
|
||||
userSource={ userSource }
|
||||
onChangeFurni={ onChangeFurniSource }
|
||||
onChangeUsers={ setUserSource } />
|
||||
) }>
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>Antenne selezionate</Text>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant={ (selectionMode === 'antenna') ? 'primary' : 'secondary' }
|
||||
onClick={ () => switchSelection('antenna') }>
|
||||
Antenne
|
||||
</Button>
|
||||
<Text small>{ selectionLimit ? `${ antennaIds.length }/${ selectionLimit }` : antennaIds.length }</Text>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>Furni selezionati</Text>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant={ (selectionMode === 'furni') ? 'primary' : 'secondary' }
|
||||
disabled={ !forwardSelectionEnabled }
|
||||
onClick={ () => switchSelection('furni') }>
|
||||
Furni
|
||||
</Button>
|
||||
<Text small>{ selectionLimit ? `${ forwardFurniIds.length }/${ selectionLimit }` : forwardFurniIds.length }</Text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{ showAdvanced && <>
|
||||
|
||||
{ /* --- Antennas --- */ }
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.sources.furni.title.signal_antenna') }</Text>
|
||||
<div className="form-check form-switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
id="signal-antenna-toggle"
|
||||
role="switch"
|
||||
checked={ antennaSource === ANTENNA_PICKED }
|
||||
onChange={ () => setAntennaSource(antennaSource === ANTENNA_PICKED ? ANTENNA_TRIGGER : ANTENNA_PICKED) } />
|
||||
<label className="form-check-label" htmlFor="signal-antenna-toggle">
|
||||
<Text small>{ LocalizeText('wiredfurni.params.sources.furni.100') }</Text>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{ /* --- Furni to forward --- */ }
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.sources.furni.title.signal_forward') }</Text>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="form-check form-switch flex-1 mb-0">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
id="signal-furni-toggle"
|
||||
role="switch"
|
||||
checked={ furniForward !== FORWARD_NONE }
|
||||
onChange={ e => setFurniForward(e.target.checked ? FORWARD_TRIGGER : FORWARD_NONE) } />
|
||||
<label className="form-check-label" htmlFor="signal-furni-toggle">
|
||||
<Text small>{ LocalizeText('wiredfurni.params.sources.furni.200') }</Text>
|
||||
</label>
|
||||
</div>
|
||||
{ furniForward !== FORWARD_NONE &&
|
||||
<select
|
||||
className="form-select form-select-sm"
|
||||
style={ { width: 'auto', minWidth: '160px' } }
|
||||
value={ furniForward }
|
||||
onChange={ e => setFurniForward(parseInt(e.target.value)) }>
|
||||
{ FURNI_FORWARD_OPTIONS.map(opt =>
|
||||
<option key={ opt.value } value={ opt.value }>{ LocalizeText(opt.label) }</option>
|
||||
) }
|
||||
</select>
|
||||
}
|
||||
</div>
|
||||
|
||||
{ /* --- Users to forward --- */ }
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.sources.users.title.signal_forward') }</Text>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="form-check form-switch flex-1 mb-0">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
id="signal-user-toggle"
|
||||
role="switch"
|
||||
checked={ userForward !== FORWARD_NONE }
|
||||
onChange={ e => setUserForward(e.target.checked ? FORWARD_TRIGGER : FORWARD_NONE) } />
|
||||
<label className="form-check-label" htmlFor="signal-user-toggle">
|
||||
<Text small>{ LocalizeText('wiredfurni.params.sources.users.0') }</Text>
|
||||
</label>
|
||||
</div>
|
||||
{ userForward !== FORWARD_NONE &&
|
||||
<select
|
||||
className="form-select form-select-sm"
|
||||
style={ { width: 'auto', minWidth: '160px' } }
|
||||
value={ userForward }
|
||||
onChange={ e => setUserForward(parseInt(e.target.value)) }>
|
||||
{ USER_FORWARD_OPTIONS.map(opt =>
|
||||
<option key={ opt.value } value={ opt.value }>{ LocalizeText(opt.label) }</option>
|
||||
) }
|
||||
</select>
|
||||
}
|
||||
</div>
|
||||
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.signal.options') }</Text>
|
||||
<div className="form-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
id="signal-per-furni"
|
||||
checked={ signalPerFurni }
|
||||
onChange={ e => setSignalPerFurni(e.target.checked) } />
|
||||
<label className="form-check-label" htmlFor="signal-per-furni">
|
||||
<Text small>{ LocalizeText('wiredfurni.params.signal.split_furni') }</Text>
|
||||
</label>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
id="signal-per-user"
|
||||
checked={ signalPerUser }
|
||||
onChange={ e => setSignalPerUser(e.target.checked) } />
|
||||
<label className="form-check-label" htmlFor="signal-per-user">
|
||||
<Text small>{ LocalizeText('wiredfurni.params.signal.split_users') }</Text>
|
||||
</label>
|
||||
</div>
|
||||
</> }
|
||||
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.signal.options') }</Text>
|
||||
<div className="form-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
id="signal-per-furni"
|
||||
checked={ signalPerFurni }
|
||||
onChange={ e => setSignalPerFurni(e.target.checked) } />
|
||||
<label className="form-check-label" htmlFor="signal-per-furni">
|
||||
<Text small>{ LocalizeText('wiredfurni.params.signal.split_furni') }</Text>
|
||||
</label>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
id="signal-per-user"
|
||||
checked={ signalPerUser }
|
||||
onChange={ e => setSignalPerUser(e.target.checked) } />
|
||||
<label className="form-check-label" htmlFor="signal-per-user">
|
||||
<Text small>{ LocalizeText('wiredfurni.params.signal.split_users') }</Text>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</WiredActionBaseView>
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionSetFurniStateToView: FC<{}> = props =>
|
||||
{
|
||||
@@ -10,18 +11,34 @@ export const WiredActionSetFurniStateToView: FC<{}> = props =>
|
||||
const [ directionFlag, setDirectionFlag ] = useState(0);
|
||||
const [ positionFlag, setPositionFlag ] = useState(0);
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 3) return trigger.intData[3];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
const save = () => setIntParams([ stateFlag, directionFlag, positionFlag ]);
|
||||
const save = () => setIntParams([ stateFlag, directionFlag, positionFlag, furniSource ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setStateFlag(trigger.getBoolean(0) ? 1 : 0);
|
||||
setDirectionFlag(trigger.getBoolean(1) ? 1 : 0);
|
||||
setPositionFlag(trigger.getBoolean(2) ? 1 : 0);
|
||||
|
||||
if(trigger.intData.length > 3) setFurniSource(trigger.intData[3]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID;
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }>
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.conditions') }</Text>
|
||||
<div className="flex items-center gap-1">
|
||||
|
||||
@@ -1,8 +1,55 @@
|
||||
import { FC } from 'react';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { WiredFurniType } from '../../../../api';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredActionTeleportView: FC<{}> = props =>
|
||||
{
|
||||
return <WiredActionBaseView hasSpecialInput={ false } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />;
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 1) return trigger.intData[0];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 2) return trigger.intData[1];
|
||||
return 0;
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
|
||||
if(trigger.intData.length >= 1) setFurniSource(trigger.intData[0]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
|
||||
if(trigger.intData.length >= 2) setUserSource(trigger.intData[1]);
|
||||
else setUserSource(0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const save = () => setIntParams([ furniSource, userSource ]);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT;
|
||||
|
||||
return (
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={
|
||||
<WiredSourcesSelector
|
||||
showFurni={ true }
|
||||
showUsers={ true }
|
||||
furniSource={ furniSource }
|
||||
userSource={ userSource }
|
||||
onChangeFurni={ onChangeFurniSource }
|
||||
onChangeUsers={ setUserSource } />
|
||||
} />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,37 @@
|
||||
import { FC } from 'react';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { WiredFurniType } from '../../../../api';
|
||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
import { useWired } from '../../../../hooks';
|
||||
|
||||
export const WiredActionToggleFurniStateView: FC<{}> = props =>
|
||||
{
|
||||
return <WiredActionBaseView hasSpecialInput={ false } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />;
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 1) return trigger.intData[0];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
|
||||
if(trigger.intData.length >= 1) setFurniSource(trigger.intData[0]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const save = () => setIntParams([ furniSource ]);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT;
|
||||
|
||||
return (
|
||||
<WiredActionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> } />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredConditionBaseView } from './WiredConditionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
const ALLOWED_HAND_ITEM_IDS: number[] = [ 2, 5, 7, 8, 9, 10, 27 ];
|
||||
|
||||
@@ -10,16 +11,26 @@ export const WiredConditionActorHasHandItemView: FC<{}> = props =>
|
||||
{
|
||||
const [ handItemId, setHandItemId ] = useState(-1);
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 1) return trigger.intData[1];
|
||||
return 0;
|
||||
});
|
||||
|
||||
const save = () => setIntParams([ handItemId ]);
|
||||
const save = () => setIntParams([ handItemId, userSource ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setHandItemId((trigger.intData.length > 0) ? trigger.intData[0] : 0);
|
||||
setUserSource((trigger.intData.length > 1) ? trigger.intData[1] : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
return (
|
||||
<WiredConditionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
|
||||
<WiredConditionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.handitem') }</Text>
|
||||
<select className="form-select form-select-sm" value={ handItemId } onChange={ event => setHandItemId(parseInt(event.target.value)) }>
|
||||
|
||||
@@ -1,8 +1,32 @@
|
||||
import { FC } from 'react';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { WiredFurniType } from '../../../../api';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredConditionBaseView } from './WiredConditionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredConditionActorIsGroupMemberView: FC<{}> = props =>
|
||||
{
|
||||
return <WiredConditionBaseView hasSpecialInput={ false } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null } />;
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 1) return trigger.intData[0];
|
||||
return 0;
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
if(trigger.intData.length >= 1) setUserSource(trigger.intData[0]);
|
||||
else setUserSource(0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const save = () => setIntParams([ userSource ]);
|
||||
|
||||
return (
|
||||
<WiredConditionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> } />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,53 @@
|
||||
import { FC } from 'react';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { WiredFurniType } from '../../../../api';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredConditionBaseView } from './WiredConditionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredConditionActorIsOnFurniView: FC<{}> = props =>
|
||||
{
|
||||
return <WiredConditionBaseView hasSpecialInput={ false } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ null } />;
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 0) return trigger.intData[0];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 1) return trigger.intData[1];
|
||||
return 0;
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
|
||||
if(trigger.intData.length > 0) setFurniSource(trigger.intData[0]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
|
||||
if(trigger.intData.length > 1) setUserSource(trigger.intData[1]);
|
||||
else setUserSource(0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const save = () => setIntParams([ furniSource, userSource ]);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID;
|
||||
|
||||
return (
|
||||
<WiredConditionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ (
|
||||
<WiredSourcesSelector
|
||||
showFurni={ true }
|
||||
showUsers={ true }
|
||||
furniSource={ furniSource }
|
||||
userSource={ userSource }
|
||||
onChangeFurni={ onChangeFurniSource }
|
||||
onChangeUsers={ setUserSource } />
|
||||
) } />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredConditionBaseView } from './WiredConditionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
const teamIds: number[] = [ 1, 2, 3, 4 ];
|
||||
|
||||
@@ -10,16 +11,26 @@ export const WiredConditionActorIsTeamMemberView: FC<{}> = props =>
|
||||
{
|
||||
const [ selectedTeam, setSelectedTeam ] = useState(-1);
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 1) return trigger.intData[1];
|
||||
return 0;
|
||||
});
|
||||
|
||||
const save = () => setIntParams([ selectedTeam ]);
|
||||
const save = () => setIntParams([ selectedTeam, userSource ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setSelectedTeam((trigger.intData.length > 0) ? trigger.intData[0] : 0);
|
||||
setUserSource((trigger.intData.length > 1) ? trigger.intData[1] : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
return (
|
||||
<WiredConditionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
|
||||
<WiredConditionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.team') }</Text>
|
||||
{ teamIds.map(value =>
|
||||
|
||||
@@ -4,21 +4,37 @@ import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { NitroInput } from '../../../../layout';
|
||||
import { WiredConditionBaseView } from './WiredConditionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredConditionActorIsWearingBadgeView: FC<{}> = props =>
|
||||
{
|
||||
const [ badge, setBadge ] = useState('');
|
||||
const { trigger = null, setStringParam = null } = useWired();
|
||||
const { trigger = null, setStringParam = null, setIntParams = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 1) return trigger.intData[0];
|
||||
return 0;
|
||||
});
|
||||
|
||||
const save = () => setStringParam(badge);
|
||||
const save = () =>
|
||||
{
|
||||
setStringParam(badge);
|
||||
setIntParams([ userSource ]);
|
||||
};
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setBadge(trigger.stringData);
|
||||
if(trigger.intData.length >= 1) setUserSource(trigger.intData[0]);
|
||||
else setUserSource(0);
|
||||
}, [ trigger ]);
|
||||
|
||||
return (
|
||||
<WiredConditionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
|
||||
<WiredConditionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.badgecode') }</Text>
|
||||
<NitroInput type="text" value={ badge } onChange={ event => setBadge(event.target.value) } />
|
||||
|
||||
@@ -4,21 +4,33 @@ import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { NitroInput } from '../../../../layout';
|
||||
import { WiredConditionBaseView } from './WiredConditionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredConditionActorIsWearingEffectView: FC<{}> = props =>
|
||||
{
|
||||
const [ effect, setEffect ] = useState(-1);
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 1) return trigger.intData[1];
|
||||
return 0;
|
||||
});
|
||||
|
||||
const save = () => setIntParams([ effect ]);
|
||||
const save = () => setIntParams([ effect, userSource ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setEffect(trigger?.intData[0] ?? 0);
|
||||
if(trigger?.intData?.length > 1) setUserSource(trigger.intData[1]);
|
||||
else setUserSource(0);
|
||||
}, [ trigger ]);
|
||||
|
||||
return (
|
||||
<WiredConditionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
|
||||
<WiredConditionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.tooltip.effectid') }</Text>
|
||||
<NitroInput type="number" value={ effect } onChange={ event => setEffect(parseInt(event.target.value)) } />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FC, PropsWithChildren } from 'react';
|
||||
import { FC, PropsWithChildren, ReactNode } from 'react';
|
||||
import { WiredFurniType } from '../../../../api';
|
||||
import { WiredBaseView } from '../WiredBaseView';
|
||||
|
||||
@@ -7,16 +7,17 @@ export interface WiredConditionBaseViewProps
|
||||
hasSpecialInput: boolean;
|
||||
requiresFurni: number;
|
||||
save: () => void;
|
||||
footer?: ReactNode;
|
||||
}
|
||||
|
||||
export const WiredConditionBaseView: FC<PropsWithChildren<WiredConditionBaseViewProps>> = props =>
|
||||
{
|
||||
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, hasSpecialInput = false, children = null } = props;
|
||||
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, hasSpecialInput = false, children = null, footer = null } = props;
|
||||
|
||||
const onSave = () => (save && save());
|
||||
|
||||
return (
|
||||
<WiredBaseView hasSpecialInput={ hasSpecialInput } requiresFurni={ requiresFurni } save={ onSave } wiredType="condition">
|
||||
<WiredBaseView hasSpecialInput={ hasSpecialInput } requiresFurni={ requiresFurni } save={ onSave } wiredType="condition" footer={ footer }>
|
||||
{ children }
|
||||
</WiredBaseView>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,36 @@
|
||||
import { FC } from 'react';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { WiredFurniType } from '../../../../api';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredConditionBaseView } from './WiredConditionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredConditionFurniHasAvatarOnView: FC<{}> = props =>
|
||||
{
|
||||
return <WiredConditionBaseView hasSpecialInput={ false } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ null } />;
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 1) return trigger.intData[0];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
if(trigger.intData.length >= 1) setFurniSource(trigger.intData[0]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const save = () => setIntParams([ furniSource ]);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID;
|
||||
|
||||
return (
|
||||
<WiredConditionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> } />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,21 +3,37 @@ import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredConditionBaseView } from './WiredConditionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredConditionFurniHasFurniOnView: FC<{}> = props =>
|
||||
{
|
||||
const [ requireAll, setRequireAll ] = useState(-1);
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 1) return trigger.intData[1];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
const save = () => setIntParams([ requireAll ]);
|
||||
const save = () => setIntParams([ requireAll, furniSource ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setRequireAll((trigger.intData.length > 0) ? trigger.intData[0] : 0);
|
||||
if(trigger.intData.length > 1) setFurniSource(trigger.intData[1]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID;
|
||||
|
||||
return (
|
||||
<WiredConditionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }>
|
||||
<WiredConditionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.requireall') }</Text>
|
||||
{ [ 0, 1 ].map(value =>
|
||||
|
||||
@@ -3,21 +3,37 @@ import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredConditionBaseView } from './WiredConditionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredConditionFurniHasNotFurniOnView: FC<{}> = props =>
|
||||
{
|
||||
const [ requireAll, setRequireAll ] = useState(-1);
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 1) return trigger.intData[1];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
const save = () => setIntParams([ requireAll ]);
|
||||
const save = () => setIntParams([ requireAll, furniSource ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setRequireAll((trigger.intData.length > 0) ? trigger.intData[0] : 0);
|
||||
if(trigger.intData.length > 1) setFurniSource(trigger.intData[1]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID;
|
||||
|
||||
return (
|
||||
<WiredConditionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }>
|
||||
<WiredConditionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.not_requireall') }</Text>
|
||||
{ [ 0, 1 ].map(value =>
|
||||
|
||||
@@ -1,8 +1,36 @@
|
||||
import { FC } from 'react';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { WiredFurniType } from '../../../../api';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredConditionBaseView } from './WiredConditionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredConditionFurniIsOfTypeView: FC<{}> = props =>
|
||||
{
|
||||
return <WiredConditionBaseView hasSpecialInput={ false } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } save={ null } />;
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length >= 1) return trigger.intData[0];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
if(trigger.intData.length >= 1) setFurniSource(trigger.intData[0]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const save = () => setIntParams([ furniSource ]);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE;
|
||||
|
||||
return (
|
||||
<WiredConditionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> } />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredConditionBaseView } from './WiredConditionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredConditionFurniMatchesSnapshotView: FC<{}> = props =>
|
||||
{
|
||||
@@ -10,18 +11,33 @@ export const WiredConditionFurniMatchesSnapshotView: FC<{}> = props =>
|
||||
const [ directionFlag, setDirectionFlag ] = useState(0);
|
||||
const [ positionFlag, setPositionFlag ] = useState(0);
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ furniSource, setFurniSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 3) return trigger.intData[3];
|
||||
return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0;
|
||||
});
|
||||
|
||||
const save = () => setIntParams([ stateFlag, directionFlag, positionFlag ]);
|
||||
const save = () => setIntParams([ stateFlag, directionFlag, positionFlag, furniSource ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setStateFlag(trigger.getBoolean(0) ? 1 : 0);
|
||||
setDirectionFlag(trigger.getBoolean(1) ? 1 : 0);
|
||||
setPositionFlag(trigger.getBoolean(2) ? 1 : 0);
|
||||
if(trigger.intData.length > 3) setFurniSource(trigger.intData[3]);
|
||||
else setFurniSource((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0);
|
||||
}, [ trigger ]);
|
||||
|
||||
const onChangeFurniSource = (next: number) => setFurniSource(next);
|
||||
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID;
|
||||
|
||||
return (
|
||||
<WiredConditionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }>
|
||||
<WiredConditionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ requiresFurni }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showFurni={ true } furniSource={ furniSource } onChangeFurni={ onChangeFurniSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.conditions') }</Text>
|
||||
<div className="flex items-center gap-1">
|
||||
|
||||
@@ -3,14 +3,20 @@ import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Slider, Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredConditionBaseView } from './WiredConditionBaseView';
|
||||
import { WiredSourcesSelector } from '../WiredSourcesSelector';
|
||||
|
||||
export const WiredConditionUserCountInRoomView: FC<{}> = props =>
|
||||
{
|
||||
const [ min, setMin ] = useState(1);
|
||||
const [ max, setMax ] = useState(0);
|
||||
const { trigger = null, setIntParams = null } = useWired();
|
||||
const [ userSource, setUserSource ] = useState<number>(() =>
|
||||
{
|
||||
if(trigger?.intData?.length > 2) return trigger.intData[2];
|
||||
return 0;
|
||||
});
|
||||
|
||||
const save = () => setIntParams([ min, max ]);
|
||||
const save = () => setIntParams([ min, max, userSource ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
@@ -24,10 +30,16 @@ export const WiredConditionUserCountInRoomView: FC<{}> = props =>
|
||||
setMin(1);
|
||||
setMax(0);
|
||||
}
|
||||
if(trigger.intData.length > 2) setUserSource(trigger.intData[2]);
|
||||
else setUserSource(0);
|
||||
}, [ trigger ]);
|
||||
|
||||
return (
|
||||
<WiredConditionBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
|
||||
<WiredConditionBaseView
|
||||
hasSpecialInput={ true }
|
||||
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
|
||||
save={ save }
|
||||
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } onChangeUsers={ setUserSource } /> }>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.usercountmin', [ 'value' ], [ min.toString() ]) }</Text>
|
||||
<Slider
|
||||
|
||||
@@ -1,35 +1,24 @@
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa';
|
||||
import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Button, Text } from '../../../../common';
|
||||
import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredActionBaseView } from '../actions/WiredActionBaseView';
|
||||
|
||||
const SOURCE_FURNI_PICKED = 0;
|
||||
const SOURCE_FURNI_SIGNAL = 1;
|
||||
const SOURCE_FURNI_TRIGGER = 2;
|
||||
|
||||
const SOURCES = [
|
||||
{ value: SOURCE_FURNI_PICKED, label: 'wiredfurni.params.sources.furni.100' },
|
||||
{ value: SOURCE_FURNI_SIGNAL, label: 'wiredfurni.params.sources.furni.201' },
|
||||
{ value: SOURCE_FURNI_TRIGGER, label: 'wiredfurni.params.sources.furni.0' },
|
||||
];
|
||||
|
||||
export const WiredSelectorFurniByTypeView: FC<{}> = () =>
|
||||
{
|
||||
const [ sourceType, setSourceType ] = useState(SOURCE_FURNI_PICKED);
|
||||
const [ matchState, setMatchState ] = useState(false);
|
||||
const [ filterExisting, setFilterExisting ] = useState(false);
|
||||
const [ invert, setInvert ] = useState(false);
|
||||
|
||||
const { trigger = null, furniIds = [], setIntParams, setSelectByType, setInvertSelection } = useWired();
|
||||
const { trigger = null, setIntParams, setSelectByType } = useWired();
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
|
||||
const p = trigger.intData;
|
||||
if(p.length >= 1) setSourceType(p[0]);
|
||||
if(p.length >= 2) setMatchState(p[1] === 1);
|
||||
if(p.length >= 3) setFilterExisting(p[2] === 1);
|
||||
if(p.length >= 4) setInvert(p[3] === 1);
|
||||
@@ -37,38 +26,20 @@ export const WiredSelectorFurniByTypeView: FC<{}> = () =>
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setSelectByType(sourceType === SOURCE_FURNI_PICKED);
|
||||
}, [ sourceType, setSelectByType ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setInvertSelection(invert);
|
||||
}, [ invert, setInvertSelection ]);
|
||||
setSelectByType(true);
|
||||
}, [ setSelectByType ]);
|
||||
|
||||
const save = useCallback(() =>
|
||||
{
|
||||
setIntParams([
|
||||
sourceType,
|
||||
SOURCE_FURNI_PICKED,
|
||||
matchState ? 1 : 0,
|
||||
filterExisting ? 1 : 0,
|
||||
invert ? 1 : 0,
|
||||
]);
|
||||
}, [ sourceType, matchState, filterExisting, invert, setIntParams ]);
|
||||
}, [ matchState, filterExisting, invert, setIntParams ]);
|
||||
|
||||
const sourceIndex = SOURCES.findIndex(s => s.value === sourceType);
|
||||
|
||||
const prevSource = () =>
|
||||
setSourceType(SOURCES[(sourceIndex - 1 + SOURCES.length) % SOURCES.length].value);
|
||||
|
||||
const nextSource = () =>
|
||||
setSourceType(SOURCES[(sourceIndex + 1) % SOURCES.length].value);
|
||||
|
||||
const requiresFurni = sourceType === SOURCE_FURNI_PICKED
|
||||
? WiredFurniType.STUFF_SELECTION_OPTION_BY_ID
|
||||
: WiredFurniType.STUFF_SELECTION_OPTION_NONE;
|
||||
|
||||
const pickedCount = furniIds.length;
|
||||
const pickedLimit = trigger?.maximumItemSelectionCount ?? 20;
|
||||
const requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_BY_ID;
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ requiresFurni } save={ save } hideDelay={ true } cardStyle={ { width: 400 } }>
|
||||
@@ -104,22 +75,6 @@ export const WiredSelectorFurniByTypeView: FC<{}> = () =>
|
||||
onChange={ e => setInvert(e.target.checked) } />
|
||||
<Text small>{ LocalizeText('wiredfurni.params.selector_option.1') }</Text>
|
||||
</label>
|
||||
|
||||
<hr className="m-0 bg-dark" />
|
||||
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.sources.furni.title') }</Text>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="primary" className="px-2 py-1" onClick={ prevSource }>
|
||||
<FaChevronLeft />
|
||||
</Button>
|
||||
<div className="flex flex-1 items-center justify-center">
|
||||
<Text small>{ LocalizeText(SOURCES[sourceIndex >= 0 ? sourceIndex : 0].label) }</Text>
|
||||
</div>
|
||||
<Button variant="primary" className="px-2 py-1" onClick={ nextSource }>
|
||||
<FaChevronRight />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</WiredActionBaseView>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { FriendlyTime, LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Text } from '../../../../common';
|
||||
import { Slider, Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredTriggerBaseView } from './WiredTriggerBaseView';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { GetWiredTimeLocale, LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Text } from '../../../../common';
|
||||
import { Slider, Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredTriggerBaseView } from './WiredTriggerBaseView';
|
||||
|
||||
|
||||
@@ -4,12 +4,14 @@ import { Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredTriggerBaseView } from './WiredTriggerBaseView';
|
||||
|
||||
const ANTENNA_INTERACTION_TYPES = [ 'antenna' ];
|
||||
|
||||
export const WiredTriggerReceiveSignalView: FC<{}> = () =>
|
||||
{
|
||||
const [ senderCount, setSenderCount ] = useState(0);
|
||||
const [ maxSenders, setMaxSenders ] = useState(5);
|
||||
|
||||
const { trigger = null } = useWired();
|
||||
const { trigger = null, setAllowedInteractionTypes } = useWired();
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
@@ -20,8 +22,15 @@ export const WiredTriggerReceiveSignalView: FC<{}> = () =>
|
||||
if(p.length >= 3) setMaxSenders(p[2]);
|
||||
}, [ trigger ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setAllowedInteractionTypes(ANTENNA_INTERACTION_TYPES);
|
||||
|
||||
return () => setAllowedInteractionTypes(null);
|
||||
}, [ setAllowedInteractionTypes ]);
|
||||
|
||||
return (
|
||||
<WiredTriggerBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null }>
|
||||
<WiredTriggerBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ null }>
|
||||
<div className="flex items-center justify-between">
|
||||
<Text small>{ LocalizeText('wiredfurni.params.signal.senders_connected') }</Text>
|
||||
<Text bold small>{ senderCount }/{ maxSenders }</Text>
|
||||
|
||||
@@ -14,9 +14,9 @@ const useWiredState = () =>
|
||||
const [ actionDelay, setActionDelay ] = useState<number>(0);
|
||||
const [ allowsFurni, setAllowsFurni ] = useState<number>(WiredFurniType.STUFF_SELECTION_OPTION_NONE);
|
||||
const [ selectByType, setSelectByType ] = useState<boolean>(false);
|
||||
const [ invertSelection, setInvertSelection ] = useState<boolean>(false);
|
||||
const [ neighborhoodTiles, setNeighborhoodTiles ] = useState<{ x: number; y: number }[] | null>(null);
|
||||
const [ neighborhoodInvert, setNeighborhoodInvert ] = useState<boolean>(false);
|
||||
const [ allowedInteractionTypes, setAllowedInteractionTypes ] = useState<string[] | null>(null);
|
||||
const { showConfirm = null, simpleAlert = null } = useNotification();
|
||||
|
||||
const saveWired = () =>
|
||||
@@ -60,6 +60,30 @@ const useWiredState = () =>
|
||||
|
||||
if(objectId <= 0) return;
|
||||
|
||||
const getInteractionTypeName = (furniData: any): string =>
|
||||
{
|
||||
if(!furniData) return null;
|
||||
|
||||
const rawValue = (furniData as any).interactionType
|
||||
?? (furniData as any).interactionTypeName
|
||||
?? (furniData as any).interactionTypeId;
|
||||
|
||||
if(rawValue === undefined || rawValue === null) return null;
|
||||
if(typeof rawValue !== 'string') return null;
|
||||
|
||||
return rawValue.toLowerCase();
|
||||
};
|
||||
|
||||
const isAllowedInteraction = (furniData: any): boolean =>
|
||||
{
|
||||
if(!allowedInteractionTypes || !allowedInteractionTypes.length) return true;
|
||||
|
||||
const interactionType = getInteractionTypeName(furniData);
|
||||
if(!interactionType) return true;
|
||||
|
||||
return allowedInteractionTypes.some(type => (type && type.toLowerCase() === interactionType));
|
||||
};
|
||||
|
||||
if(selectByType && category === RoomObjectCategory.FLOOR)
|
||||
{
|
||||
const roomId = GetRoomSession().roomId;
|
||||
@@ -71,6 +95,21 @@ const useWiredState = () =>
|
||||
const sourceFurniData = GetSessionDataManager().getFloorItemData(typeId);
|
||||
|
||||
if(!sourceFurniData) return;
|
||||
if(!isAllowedInteraction(sourceFurniData))
|
||||
{
|
||||
setFurniIds(prevValue =>
|
||||
{
|
||||
if(!prevValue.includes(objectId)) return prevValue;
|
||||
|
||||
const remaining = prevValue.filter(id => id !== objectId);
|
||||
|
||||
WiredSelectionVisualizer.hide(objectId);
|
||||
|
||||
return remaining;
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const matchFurniLine = sourceFurniData.furniLine;
|
||||
const matchName = sourceFurniData.name;
|
||||
@@ -84,6 +123,8 @@ const useWiredState = () =>
|
||||
const fd = GetSessionDataManager().getFloorItemData(tId);
|
||||
if(!fd) return false;
|
||||
|
||||
if(!isAllowedInteraction(fd)) return false;
|
||||
|
||||
const furniLineMatch = matchFurniLine && matchFurniLine.length > 0 && fd.furniLine === matchFurniLine;
|
||||
return furniLineMatch || fd.name === matchName;
|
||||
};
|
||||
@@ -102,10 +143,8 @@ const useWiredState = () =>
|
||||
}
|
||||
|
||||
// ── Select a new group ──────────────────────────────────────
|
||||
if(prevValue && prevValue.length) WiredSelectionVisualizer.clearSelectionShaderFromFurni(prevValue);
|
||||
|
||||
const allFloorObjects = GetRoomEngine().getRoomObjects(roomId, RoomObjectCategory.FLOOR);
|
||||
const newIds: number[] = [];
|
||||
const newIds = [ ...prevValue ];
|
||||
const limit = trigger.maximumItemSelectionCount;
|
||||
|
||||
for(const obj of allFloorObjects)
|
||||
@@ -116,14 +155,16 @@ const useWiredState = () =>
|
||||
const tId = obj.model.getValue<number>(RoomObjectVariable.FURNITURE_TYPE_ID);
|
||||
const fd = GetSessionDataManager().getFloorItemData(tId);
|
||||
if(!fd) continue;
|
||||
if(!isAllowedInteraction(fd)) continue;
|
||||
|
||||
const furniLineMatch = matchFurniLine && matchFurniLine.length > 0 && fd.furniLine === matchFurniLine;
|
||||
const matches = furniLineMatch || fd.name === matchName;
|
||||
|
||||
if(invertSelection ? !matches : matches) newIds.push(obj.id);
|
||||
if(matches && !newIds.includes(obj.id)) newIds.push(obj.id);
|
||||
}
|
||||
|
||||
WiredSelectionVisualizer.applySelectionShaderToFurni(newIds);
|
||||
const addedIds = newIds.filter(id => !prevValue.includes(id));
|
||||
if(addedIds.length) WiredSelectionVisualizer.applySelectionShaderToFurni(addedIds);
|
||||
|
||||
return newIds;
|
||||
});
|
||||
@@ -131,6 +172,34 @@ const useWiredState = () =>
|
||||
return;
|
||||
}
|
||||
|
||||
if(category === RoomObjectCategory.FLOOR && allowedInteractionTypes && allowedInteractionTypes.length)
|
||||
{
|
||||
const roomId = GetRoomSession().roomId;
|
||||
const clickedObject = GetRoomEngine().getRoomObject(roomId, objectId, RoomObjectCategory.FLOOR);
|
||||
|
||||
if(!clickedObject) return;
|
||||
|
||||
const typeId = clickedObject.model.getValue<number>(RoomObjectVariable.FURNITURE_TYPE_ID);
|
||||
const sourceFurniData = GetSessionDataManager().getFloorItemData(typeId);
|
||||
|
||||
if(!sourceFurniData) return;
|
||||
if(!isAllowedInteraction(sourceFurniData))
|
||||
{
|
||||
setFurniIds(prevValue =>
|
||||
{
|
||||
if(!prevValue.includes(objectId)) return prevValue;
|
||||
|
||||
const remaining = prevValue.filter(id => id !== objectId);
|
||||
|
||||
WiredSelectionVisualizer.hide(objectId);
|
||||
|
||||
return remaining;
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setFurniIds(prevValue =>
|
||||
{
|
||||
const newFurniIds = [ ...prevValue ];
|
||||
@@ -217,13 +286,13 @@ const useWiredState = () =>
|
||||
});
|
||||
setAllowsFurni(WiredFurniType.STUFF_SELECTION_OPTION_NONE);
|
||||
setSelectByType(false);
|
||||
setInvertSelection(false);
|
||||
setNeighborhoodTiles(null);
|
||||
setNeighborhoodInvert(false);
|
||||
setAllowedInteractionTypes(null);
|
||||
};
|
||||
}, [ trigger ]);
|
||||
|
||||
return { trigger, setTrigger, intParams, setIntParams, stringParam, setStringParam, furniIds, setFurniIds, actionDelay, setActionDelay, setAllowsFurni, saveWired, selectObjectForWired, setSelectByType, setInvertSelection, setNeighborhoodTiles, setNeighborhoodInvert };
|
||||
return { trigger, setTrigger, intParams, setIntParams, stringParam, setStringParam, furniIds, setFurniIds, actionDelay, setActionDelay, setAllowsFurni, saveWired, selectObjectForWired, setSelectByType, setNeighborhoodTiles, setNeighborhoodInvert, setAllowedInteractionTypes };
|
||||
};
|
||||
|
||||
export const useWired = () => useBetween(useWiredState);
|
||||
|
||||
Reference in New Issue
Block a user