5180 fichiers 38.5 Mo 0 téléchargements 377 vues mis à jour il y a 7 heures ui
nitro-v36-with-renderer-v36 / src / components / wired / views / conditions / WiredConditionTeamHasScoreView.tsx
WiredConditionTeamHasScoreView.tsx 7.8 Ko Télécharger le fichier
import { FC, useEffect, useState } from 'react';
import { LocalizeText, localizeWithFallback, WiredFurniType } from '../../../../api';
import { Slider, Text } from '../../../../common';
import { useWired } from '../../../../hooks';
import { normalizeWiredComparison, WIRED_CMP_GREATER_EQUAL, WiredComparisonOperator } from '../WiredComparisonOperator';
import { WiredSourcesSelector } from '../WiredSourcesSelector';
import { WiredConditionBaseView } from './WiredConditionBaseView';
import { WiredConditionQuantifierSection } from './WiredConditionQuantifierSection';
import { Radio } from '../../../../common/Radio';
import { BaseButton } from '../../../../common/BaseButton';
import { NativeTextTree } from '../../../../common/native-text/NativeTextTree';

// 0 is the triggering user's team, as officially.
const TEAM_OPTIONS = [0, 1, 2, 3, 4];
const COMPARISON_OPTIONS = [0, 1, 2];
const MIN_SCORE = 0;
// Official TeamHasScore slider: 0..1000.
const MAX_SCORE = 1000;
/** What the server's normalizeScore lets through. A credit threshold is useless capped at 1000. */
const MAX_AMOUNT = 1_000_000;
const SCORE_PATTERN = /^\d*$/;

const clampScore = (value: number, max: number) => {
    if (isNaN(value)) return MIN_SCORE;

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

interface WiredConditionTeamHasScoreViewProps {
    /**
     * The item-count and currency conditions share this dialog for its amount and user source. They have
     * no team, and their comparison uses the six shared wired codes rather than
     * the three team-score ones, so they pass false and get the shared operator selector instead.
     */
    scoped?: boolean;
}

export const WiredConditionTeamHasScoreView: FC<WiredConditionTeamHasScoreViewProps> = ({ scoped = true }) => {
    const { trigger = null, setIntParams = null } = useWired();
    const ceiling = scoped ? MAX_SCORE : MAX_AMOUNT;
    const [team, setTeam] = useState(1);
    const [comparison, setComparison] = useState(scoped ? 1 : WIRED_CMP_GREATER_EQUAL);
    const [score, setScore] = useState(0);
    const [scoreInput, setScoreInput] = useState('0');
    const [userSource, setUserSource] = useState(0);
    const [showAdvanced, setShowAdvanced] = useState(false);

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

        // Official team score: [team, points, comparison, ...]; the shared amount boxes keep [_, comparison, amount, ...].
        const nextTeam = trigger.intData.length > 0 ? trigger.intData[0] : 1;
        const nextComparison = trigger.intData.length > (scoped ? 2 : 1) ? trigger.intData[scoped ? 2 : 1] : scoped ? 1 : WIRED_CMP_GREATER_EQUAL;
        const nextScore = clampScore(trigger.intData.length > (scoped ? 1 : 2) ? trigger.intData[scoped ? 1 : 2] : 0, ceiling);
        const nextUserSource = trigger.intData.length > 3 ? trigger.intData[3] : 0;

        setTeam(TEAM_OPTIONS.includes(nextTeam) && (scoped || nextTeam !== 0) ? nextTeam : 1);
        setComparison(scoped ? (COMPARISON_OPTIONS.includes(nextComparison) ? nextComparison : 1) : normalizeWiredComparison(nextComparison));
        setScore(nextScore);
        setScoreInput(nextScore.toString());
        setUserSource(nextUserSource);
        setShowAdvanced(nextUserSource !== 0 || (trigger.quantifierCode ?? 0) !== 0);
    }, [ceiling, scoped, trigger]);

    const updateScore = (value: number) => {
        const nextValue = clampScore(value, ceiling);

        setScore(nextValue);
        setScoreInput(nextValue.toString());
    };

    const updateScoreInput = (value: string) => {
        if (!SCORE_PATTERN.test(value)) return;

        setScoreInput(value);

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

        updateScore(parseInt(value));
    };

    const save = () => {
        setIntParams(
            scoped
                ? [team, clampScore(score, ceiling), comparison, userSource]
                : [team, comparison, clampScore(score, ceiling), userSource]
        );
    };

    return (
        <NativeTextTree>
            <WiredConditionBaseView
                hasSpecialInput={true}
                requiresFurni={WiredFurniType.STUFF_SELECTION_OPTION_NONE}
                save={save}
                footerCollapsible={false}
                showQuantifier={false}
                footer={
                    <div className="flex flex-col gap-2">
                        <BaseButton className="octane-wired__advanced-toggle" type="button" onClick={() => setShowAdvanced((value) => !value)}>
                            {LocalizeText(showAdvanced ? 'wiredfurni.params.sources.collapse' : 'wiredfurni.params.sources.expand')}
                        </BaseButton>
                        {showAdvanced && (
                            <>
                                <WiredConditionQuantifierSection />
                                <WiredSourcesSelector showUsers={true} userSource={userSource} onChangeUsers={setUserSource} />
                            </>
                        )}
                    </div>
                }
            >
                {!scoped && <WiredComparisonOperator name="userAmountComparison" value={comparison} onChange={setComparison} />}
                {scoped && (
                    <>
                        <div className="flex flex-col gap-1">
                            <Text bold>{LocalizeText('wiredfurni.params.team')}</Text>
                            {TEAM_OPTIONS.map((value) => {
                                return (
                                    <div key={value} className="flex items-center gap-1">
                                        <Radio checked={team === value} id={`teamHasScore${value}`} name="teamHasScore" onCheckedChange={() => setTeam(value)} />
                                        <Text>{LocalizeText(value === 0 ? 'wiredfurni.params.team.triggerer' : `wiredfurni.params.team.${value}`)}</Text>
                                    </div>
                                );
                            })}
                        </div>
                        <div className="flex flex-col gap-1">
                            <Text bold>{LocalizeText('wiredfurni.params.comparison_selection')}</Text>
                            {COMPARISON_OPTIONS.map((value) => {
                                return (
                                    <div key={value} className="flex items-center gap-1">
                                        <Radio checked={comparison === value} id={`teamScoreComparison${value}`} name="teamScoreComparison" onCheckedChange={() => setComparison(value)} />
                                        <Text>{LocalizeText(`wiredfurni.params.comparison.${value}`)}</Text>
                                    </div>
                                );
                            })}
                        </div>
                    </>
                )}
                <div className="flex flex-col gap-1">
                    <Text bold>{scoped ? LocalizeText('wiredfurni.params.setscore2') : localizeWithFallback('wiredfurni.params.user_amount', 'Amount:')}</Text>
                    <input
                        className="form-control form-control-sm"
                        inputMode="numeric"
                        type="text"
                        value={scoreInput}
                        onBlur={() => setScoreInput(clampScore(score, ceiling).toString())}
                        onChange={(event) => updateScoreInput(event.target.value)}
                    />
                </div>
                {scoped && (
                    <div className="flex flex-col gap-1">
                        <Slider max={MAX_SCORE} min={MIN_SCORE} step={1} value={score} onChange={(event) => updateScore(event as number)} />
                        <Text small>{score}</Text>
                    </div>
                )}
            </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