5180 fichiers 38.5 Mo 0 téléchargements 347 vues mis à jour il y a 7 heures ui
nitro-v36-with-renderer-v36 / src / components / wired / views / extras / WiredExtraUserVariableView.tsx
WiredExtraUserVariableView.tsx 8.2 Ko Télécharger le fichier
import { FC, useEffect, useMemo, useState } from 'react';
import { LocalizeText, localizeWithFallback, WiredFurniType  } from '../../../../api';
import { Text } from '../../../../common';
import { useWired } from '../../../../hooks';
import { OctaneInput } from '../../../../layout';
import { WiredExtraBaseView } from './WiredExtraBaseView';
import { Checkbox } from '../../../../common/Checkbox';
import { Radio } from '../../../../common/Radio';
import { NativeTextTree } from '../../../../common/native-text/NativeTextTree';

const AVAILABILITY_ROOM = 0;
const AVAILABILITY_PERMANENT = 10;
const AVAILABILITY_SHARED = 11;

/** Permanent and shared user variables keep their values in the database. */
const isStoredAvailability = (availability: number) => (availability === AVAILABILITY_PERMANENT) || (availability === AVAILABILITY_SHARED);

const MAX_NAME_LENGTH = 40;

const normalizeVariableName = (value: string) =>
{
    let normalizedValue = (value ?? '').replace(/[\t\r\n]/g, '');

    if(normalizedValue.includes('=')) normalizedValue = normalizedValue.substring(0, normalizedValue.indexOf('=')).trim();

    while(normalizedValue.startsWith('@') || normalizedValue.startsWith('~'))
    {
        normalizedValue = normalizedValue.substring(1);
    }

    normalizedValue = normalizedValue.replace(/\s+/g, '_');
    normalizedValue = normalizedValue.replace(/[^A-Za-z0-9_]/g, '');

    return normalizedValue.slice(0, MAX_NAME_LENGTH);
};

const handleVariableNameKeyDown = (event: React.KeyboardEvent<HTMLInputElement>, setValue: (value: string) => void) =>
{
    if(event.key !== ' ') return;

    event.preventDefault();

    const input = event.currentTarget;
    const start = (input.selectionStart ?? input.value.length);
    const end = (input.selectionEnd ?? start);
    const nextValue = `${ input.value.substring(0, start) }_${ input.value.substring(end) }`;

    setValue(normalizeVariableName(nextValue));

    window.requestAnimationFrame(() => input.setSelectionRange(Math.min(start + 1, input.value.length + 1), Math.min(start + 1, input.value.length + 1)));
};

interface WiredExtraVariableViewProps
{
    availabilityRoomValue: number;
    availabilityRoomText: string;
    availabilityRadioName: string;
    showSharedAvailability?: boolean;
    /** AIR: a user variable sends [availability, hasValue], a furni variable [hasValue, availability]. */
    availabilityFirst?: boolean;
}

export const WiredExtraVariableView: FC<WiredExtraVariableViewProps> = props =>
{
    const { trigger = null, setIntParams = null, setStringParam = null } = useWired();
    const [ variableName, setVariableName ] = useState('');
    const [ hasValue, setHasValue ] = useState(false);
    const [ availability, setAvailability ] = useState(props.availabilityRoomValue);
    const roomAvailabilityText = useMemo(() =>
    {
        const localizedText = props.availabilityRoomText;

        if(localizedText && (localizedText !== 'wiredfurni.params.variables.availability.1')) return localizedText;

        return localizeWithFallback('wiredfurni.condition.room.active', 'While the room is active');
    }, [ props.availabilityRoomText ]);
    const normalizeAvailability = useMemo(() => (value: number) =>
    {
        if(props.showSharedAvailability && (value === AVAILABILITY_SHARED)) return AVAILABILITY_SHARED;
        if(value === AVAILABILITY_PERMANENT) return AVAILABILITY_PERMANENT;

        return props.availabilityRoomValue;
    }, [ props.availabilityRoomValue, props.showSharedAvailability ]);

    useEffect(() =>
    {
        if(!trigger) return;

        setVariableName(normalizeVariableName(trigger.stringData));
        const [ hasValueIndex, availabilityIndex ] = props.availabilityFirst ? [ 1, 0 ] : [ 0, 1 ];

        setHasValue((trigger.intData.length > hasValueIndex) ? (trigger.intData[hasValueIndex] === 1) : false);
        setAvailability(normalizeAvailability((trigger.intData.length > availabilityIndex) ? trigger.intData[availabilityIndex] : props.availabilityRoomValue));
    }, [ normalizeAvailability, props.availabilityFirst, props.availabilityRoomValue, trigger ]);

    const save = () =>
    {
        setStringParam(normalizeVariableName(variableName));
        const nextAvailability = normalizeAvailability(availability);

        setIntParams(props.availabilityFirst ? [ nextAvailability, hasValue ? 1 : 0 ] : [ hasValue ? 1 : 0, nextAvailability ]);
    };

    // Official (user variables only): a stored variable switched to one that is not stored loses its data, so the
    // save asks first.
    const confirmSave = () =>
    {
        if(!props.showSharedAvailability || !trigger) return null;

        const availabilityIndex = props.availabilityFirst ? 0 : 1;
        const saved = normalizeAvailability((trigger.intData.length > availabilityIndex) ? trigger.intData[availabilityIndex] : props.availabilityRoomValue);
        const next = normalizeAvailability(availability);

        if(!isStoredAvailability(saved) || isStoredAvailability(next)) return null;

        return {
            title: LocalizeText('wiredfurni.variables.availability_change.title'),
            body: LocalizeText('wiredfurni.variables.availability_change.body')
        };
    };

    return (
        <NativeTextTree>
            <WiredExtraBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save } confirmSave={ confirmSave } cardStyle={ { width: 400 } }>
                <div className="flex flex-col gap-2">
                    <div className="flex flex-col gap-1">
                        <Text>{ LocalizeText('wiredfurni.params.variables.variable_name') }</Text>
                        <OctaneInput maxLength={ MAX_NAME_LENGTH } type="text" value={ variableName } onChange={ event => setVariableName(normalizeVariableName(event.target.value)) } onKeyDown={ event => handleVariableNameKeyDown(event, setVariableName) } />
                    </div>

                    <div className="flex flex-col gap-1">
                        <Text>{ LocalizeText('wiredfurni.params.variables.settings') }</Text>
                        <label className="flex items-center gap-1 cursor-pointer">
                            <Checkbox checked={ hasValue } onCheckedChange={(nextChecked) => setHasValue(nextChecked)} />
                            <Text>{ LocalizeText('wiredfurni.params.variables.settings.has_value') }</Text>
                        </label>
                    </div>

                    <div className="flex flex-col gap-1">
                        <Text>{ LocalizeText('wiredfurni.params.variables.availability') }</Text>
                        <label className="flex items-center gap-1 cursor-pointer">
                            <Radio checked={ (availability === props.availabilityRoomValue) } name={ props.availabilityRadioName } onCheckedChange={() => setAvailability(props.availabilityRoomValue)} />
                            <Text>{ roomAvailabilityText }</Text>
                        </label>
                        <label className="flex items-center gap-1 cursor-pointer">
                            <Radio checked={ (availability === AVAILABILITY_PERMANENT) } name={ props.availabilityRadioName } onCheckedChange={() => setAvailability(AVAILABILITY_PERMANENT)} />
                            <Text>{ LocalizeText('wiredfurni.params.variables.availability.10') }</Text>
                        </label>
                        { !!props.showSharedAvailability &&
                            <label className="flex items-center gap-1 cursor-pointer">
                                <Radio checked={ (availability === AVAILABILITY_SHARED) } name={ props.availabilityRadioName } onCheckedChange={() => setAvailability(AVAILABILITY_SHARED)} />
                                <Text>{ LocalizeText('wiredfurni.params.variables.availability.11') }</Text>
                            </label> }
                    </div>
                </div>
            </WiredExtraBaseView>
        </NativeTextTree>
    );
};

export const WiredExtraUserVariableView: FC<{}> = () =>
{
    return <WiredExtraVariableView availabilityRadioName="wiredUserVariableAvailability" availabilityRoomText={ LocalizeText('wiredfurni.params.variables.availability.0') } availabilityRoomValue={ AVAILABILITY_ROOM } showSharedAvailability={ true } availabilityFirst={ true } />;
};


15Sujets
1Dépôts
20Membres
3En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser