5180 fichiers 38.5 Mo 0 téléchargements 378 vues mis à jour il y a 7 heures ui
nitro-v36-with-renderer-v36 / src / components / wired / views / conditions / WiredConditionSelectionQuantityView.tsx
WiredConditionSelectionQuantityView.tsx 9.8 Ko Télécharger le fichier
import { FC, useEffect, useMemo, useState } from 'react';
import { LocalizeText, WiredFurniType } from '../../../../api';
import sourceFurniIcon from '../../../../assets/images/wired/source_furni.png';
import sourceUserIcon from '../../../../assets/images/wired/source_user.png';
import { Button, Slider, Text } from '../../../../common';
import { useWired } from '../../../../hooks';
import { WiredFurniSelectionSourceRow } from '../WiredFurniSelectionSourceRow';
import { sortWiredSourceOptions, useAvailableUserSources } from '../WiredSourcesSelector';
import { WiredConditionBaseView } from './WiredConditionBaseView';
import { Radio } from '../../../../common/Radio';
import { BaseButton } from '../../../../common/BaseButton';
import { NativeTextTree } from '../../../../common/native-text/NativeTextTree';

const SOURCE_GROUP_USERS = 0;
const SOURCE_GROUP_FURNI = 1;
const SOURCE_TRIGGER = 0;
const SOURCE_SELECTED = 100;
const COMPARISON_OPTIONS = [0, 1, 2];
const MIN_QUANTITY = 0;
const MAX_QUANTITY = 100;
const QUANTITY_PATTERN = /^\d*$/;

const USER_SOURCES = sortWiredSourceOptions(
    [
        { value: 0, label: 'wiredfurni.params.sources.users.0' },
        { value: 200, label: 'wiredfurni.params.sources.users.200' },
        { value: 201, label: 'wiredfurni.params.sources.users.201' }
    ],
    'users'
);

const FURNI_SOURCES = sortWiredSourceOptions(
    [
        { value: 100, label: 'wiredfurni.params.sources.furni.100' },
        { value: 200, label: 'wiredfurni.params.sources.furni.200' },
        { value: 201, label: 'wiredfurni.params.sources.furni.201' },
        { value: 0, label: 'wiredfurni.params.sources.furni.0' }
    ],
    'furni'
);

const SOURCE_GROUP_BUTTONS = [
    { key: 'user', icon: sourceUserIcon, isUserGroup: true },
    { key: 'furni', icon: sourceFurniIcon, isUserGroup: false }
] as const;

const clampQuantity = (value: number) => {
    if (isNaN(value)) return MIN_QUANTITY;

    return Math.max(MIN_QUANTITY, Math.min(MAX_QUANTITY, Math.floor(value)));
};

const normalizeSourceType = (value: number, allowed: number[]) => {
    return allowed.includes(value) ? value : SOURCE_TRIGGER;
};

export const WiredConditionSelectionQuantityView: FC<{}> = () => {
    // Official layout: [merged, amount, comparison], what is counted in the official furni or user source slot.
    const { trigger = null, furniIds = [], setFurniIds = null, setIntParams = null, setStringParam = null, setSourceTypes = null } = useWired();
    const rawAvailableUserSources = useAvailableUserSources(trigger, USER_SOURCES);
    const availableUserSources = useMemo(() => sortWiredSourceOptions(rawAvailableUserSources, 'users'), [rawAvailableUserSources]);
    const [comparison, setComparison] = useState(1);
    const [quantity, setQuantity] = useState(0);
    const [quantityInput, setQuantityInput] = useState('0');
    const [sourceGroup, setSourceGroup] = useState(SOURCE_GROUP_USERS);
    const [userSource, setUserSource] = useState(SOURCE_TRIGGER);
    const [furniSource, setFurniSource] = useState(SOURCE_TRIGGER);

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

        const nextComparison = trigger.intData.length > 2 ? trigger.intData[2] : 1;
        const nextQuantity = clampQuantity(trigger.intData.length > 1 ? trigger.intData[1] : 0);
        const nextSourceGroup = (trigger.furniSourceTypes?.length ?? 0) > 0 ? SOURCE_GROUP_FURNI : SOURCE_GROUP_USERS;
        const nextSourceType = (nextSourceGroup === SOURCE_GROUP_FURNI ? trigger.furniSourceTypes?.[0] : trigger.userSourceTypes?.[0]) ?? SOURCE_TRIGGER;

        setComparison(COMPARISON_OPTIONS.includes(nextComparison) ? nextComparison : 1);
        setQuantity(nextQuantity);
        setQuantityInput(nextQuantity.toString());
        setSourceGroup(nextSourceGroup);
        setUserSource(
            nextSourceGroup === SOURCE_GROUP_USERS
                ? normalizeSourceType(
                      nextSourceType,
                      availableUserSources.map((source) => source.value)
                  )
                : SOURCE_TRIGGER
        );
        setFurniSource(
            nextSourceGroup === SOURCE_GROUP_FURNI
                ? normalizeSourceType(
                      nextSourceType,
                      FURNI_SOURCES.map((source) => source.value)
                  )
                : SOURCE_TRIGGER
        );
    }, [availableUserSources, trigger]);

    const isUserGroup = sourceGroup === SOURCE_GROUP_USERS;
    const activeSources = useMemo(() => (isUserGroup ? availableUserSources : FURNI_SOURCES), [availableUserSources, isUserGroup]);
    const activeSource = isUserGroup ? userSource : furniSource;
    const activeSourceIndex = Math.max(
        0,
        activeSources.findIndex((source) => source.value === activeSource)
    );
    const currentSourceType = activeSources[activeSourceIndex]?.value ?? SOURCE_TRIGGER;
    const requiresFurni =
        !isUserGroup && furniSource === SOURCE_SELECTED ? WiredFurniType.STUFF_SELECTION_OPTION_BY_ID : WiredFurniType.STUFF_SELECTION_OPTION_NONE;

    useEffect(() => {
        if (currentSourceType === activeSource) return;

        if (isUserGroup) setUserSource(currentSourceType);
        else setFurniSource(currentSourceType);
    }, [activeSource, currentSourceType, isUserGroup]);

    const changeGroup = (nextIsUserGroup: boolean) => {
        if (nextIsUserGroup === isUserGroup) return;

        const nextOptions = nextIsUserGroup ? availableUserSources : FURNI_SOURCES;
        const nextIndex = Math.min(activeSourceIndex, Math.max(0, nextOptions.length - 1));
        const nextOption = nextOptions[nextIndex] ?? nextOptions[0];

        setSourceGroup(nextIsUserGroup ? SOURCE_GROUP_USERS : SOURCE_GROUP_FURNI);

        if (!nextOption) return;

        if (nextIsUserGroup) setUserSource(nextOption.value);
        else setFurniSource(nextOption.value);
    };

    const updateQuantity = (value: number) => {
        const nextValue = clampQuantity(value);

        setQuantity(nextValue);
        setQuantityInput(nextValue.toString());
    };

    const updateQuantityInput = (value: string) => {
        if (!QUANTITY_PATTERN.test(value)) return;

        setQuantityInput(value);

        if (!value.length) {
            setQuantity(0);
            return;
        }

        updateQuantity(parseInt(value));
    };

    const save = () => {
        setIntParams([0, clampQuantity(quantity), comparison]);
        setStringParam('');
        setSourceTypes(isUserGroup ? { furni: [], users: [userSource] } : { furni: [furniSource], users: [] });

        if (requiresFurni <= WiredFurniType.STUFF_SELECTION_OPTION_NONE) setFurniIds([]);
    };

    return (
        <NativeTextTree>
            <WiredConditionBaseView hasSpecialInput={true} requiresFurni={requiresFurni} save={save}>
                <div className="flex flex-col gap-1">
                    <Text bold>{LocalizeText('wiredfurni.params.comparison_selection')}</Text>
                    {COMPARISON_OPTIONS.map((value) => {
                        return (
                            <label key={value} className="flex items-center gap-1">
                                <Radio checked={comparison === value} name="selectionQuantityComparison" onCheckedChange={() => setComparison(value)} />
                                <Text>{LocalizeText(`wiredfurni.params.comparison.${value}`)}</Text>
                            </label>
                        );
                    })}
                </div>
                <div className="flex flex-col gap-2">
                    <input
                        className="form-control form-control-sm"
                        inputMode="numeric"
                        max={MAX_QUANTITY}
                        min={MIN_QUANTITY}
                        type="text"
                        value={quantityInput}
                        onBlur={() => setQuantityInput(clampQuantity(quantity).toString())}
                        onChange={(event) => updateQuantityInput(event.target.value)}
                    />
                    <Slider max={MAX_QUANTITY} min={MIN_QUANTITY} step={1} value={quantity} onChange={(event) => updateQuantity(event as number)} />
                    <Text small>{quantity}</Text>
                </div>
                <WiredFurniSelectionSourceRow
                    title="wiredfurni.params.sources.merged.title"
                    options={activeSources}
                    value={activeSource}
                    selectionKind={isUserGroup ? 'primary' : 'secondary'}
                    selectionActive={!isUserGroup && furniSource === SOURCE_SELECTED}
                    selectionCount={furniIds.length}
                    selectionLimit={trigger?.maximumItemSelectionCount ?? 20}
                    selectionEnabledValues={[SOURCE_SELECTED]}
                    showSelectionToggle={false}
                    headerContent={
                        <div className="octane-wired__give-var-targets">
                            {SOURCE_GROUP_BUTTONS.map((button) => (
                                <BaseButton
                                    key={button.key}
                                    type="button"
                                    className={`octane-wired__give-var-target octane-wired__give-var-target--${button.key} ${isUserGroup === button.isUserGroup ? 'is-active' : ''}`}
                                    onClick={() => changeGroup(button.isUserGroup)}
                                >
                                    <img src={button.icon} alt={button.key} />
                                </BaseButton>
                            ))}
                        </div>
                    }
                    onChange={(value) => {
                        if (isUserGroup) setUserSource(value);
                        else setFurniSource(value);
                    }}
                />
            </WiredConditionBaseView>
        </NativeTextTree>
    );
};
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