5180 fichiers 38.5 Mo 0 téléchargements 366 vues mis à jour il y a 7 heures ui
nitro-v36-with-renderer-v36 / src / components / room / widgets / wired-contract / WiredContractElementEditorView.tsx
WiredContractElementEditorView.tsx 8.5 Ko Télécharger le fichier
import { FurnitureType, GetSessionDataManager, IWiredContractItemType, IWiredContractNode } from '@octane/renderer';
import { FC, useMemo, useState } from 'react';
import { LocalizeText } from '../../../../api';
import {
    createWiredContractNode,
    filterWiredContractCandidates,
    IWiredContractCandidate,
    validateWiredContractElement,
    WIRED_CONTRACT_COIN,
    WIRED_CONTRACT_FURNI,
    WIRED_CONTRACT_MAX_COINS,
    WIRED_CONTRACT_MAX_FURNI,
    WIRED_CONTRACT_SEARCH_MAX,
    wiredContractCandidates,
    wiredContractItemKey
} from '../../../../api/wired/WiredContract';
import { LayoutFurniIconImageView } from '../../../../common';
import { ContractFooter, ContractFrame, ContractSection, ContractSkin, ContractText } from './WiredContractEditorView';
import { BaseButton } from '../../../../common/BaseButton';
import { NumberInput } from '../../../../common/NumberInput';
import { Radio } from '../../../../common/Radio';
import { NativeTextTree } from '../../../../common/native-text/NativeTextTree';

/** AIR TableView rows are 20px; only the rows in view (and a few around them) are drawn. */
const ROW_HEIGHT = 20;
const VISIBLE_ROWS = 18;

export interface WiredContractElementEditorViewProps
{
    initial: IWiredContractNode | null;
    canWrite: boolean;
    onSave: (node: IWiredContractNode) => void;
    onClose: () => void;
    /** AIR alerts a refused element (`${wiredfurni.error.title}` with the reason). */
    onInvalid: (message: string) => void;
    /** For tests: the furnidata to list; the session's furnidata otherwise. */
    candidates?: IWiredContractCandidate[];
}

/**
 * AIR AddEditContractElement: type and amount side by side, then the item type selection (furni code, search, a
 * 234px table of name / code / type and the row count). 420px wide, 375px right of centre.
 */
export const WiredContractElementEditorView: FC<WiredContractElementEditorViewProps> = ({ initial, canWrite, onSave, onClose, onInvalid, candidates = null }) =>
{
    const [ type, setType ] = useState<number>(initial?.type ?? WIRED_CONTRACT_COIN);
    const [ amount, setAmount ] = useState(String(initial?.amount ?? 1));
    const [ selected, setSelected ] = useState<IWiredContractItemType | null>(initial?.itemType ?? null);
    const [ query, setQuery ] = useState('');
    const [ scrollTop, setScrollTop ] = useState(0);
    const all = useMemo(() => candidates ?? wiredContractCandidates(GetSessionDataManager().getAllFurnitureData() ?? [], key => LocalizeText(key)), [ candidates ]);
    const filtered = useMemo(() => filterWiredContractCandidates(all, query), [ all, query ]);
    const selectedCandidate = useMemo(() => all.find(candidate => wiredContractItemKey(candidate.itemType) === wiredContractItemKey(selected)) ?? null, [ all, selected ]);
    const first = Math.max(0, Math.floor(scrollTop / ROW_HEIGHT) - 2);
    const visible = filtered.slice(first, first + VISIBLE_ROWS);

    const save = () =>
    {
        if(!canWrite) return;

        const value = Number(amount);
        const error = validateWiredContractElement(type, value, selectedCandidate);

        if(error)
        {
            onInvalid(error === 'wiredcontracts.element.too_many_items' ? LocalizeText(error, [ 'amount' ], [ String(WIRED_CONTRACT_MAX_FURNI) ]) : LocalizeText(error));
            return;
        }

        onSave(createWiredContractNode(type, value, selectedCandidate?.itemType ?? null));
    };

    return (
        <NativeTextTree>
            <ContractFrame title={ LocalizeText(initial ? 'wiredcontracts.edit_element.title' : 'wiredcontracts.add_element.title') } width={ 420 } offsetLeft={ 375 } uniqueKey="wired-contract-element" className="wired-contract--element" onClose={ onClose }>
                <fieldset className="wired-contract__editable" disabled={ !canWrite }>
                    <div className="wired-contract__element-top">
                        <ContractSection title={ LocalizeText('wiredcontracts.element.type') }>
                            { [ WIRED_CONTRACT_COIN, WIRED_CONTRACT_FURNI ].map(value =>
                                <label className="wired-contract__choice" key={ value }>
                                    <Radio name="wired-contract-element-type" checked={ type === value } onCheckedChange={ () => setType(value) } />
                                    <ContractText text={ LocalizeText(`wiredcontracts.element.type.${ value }`) } />
                                </label>) }
                        </ContractSection>
                        <ContractSection title={ LocalizeText('wiredcontracts.element.amount') }>
                            <NumberInput className="wired-contract__input wired-contract__amount" min={ 1 } max={ WIRED_CONTRACT_MAX_COINS } aria-label={ LocalizeText('wiredcontracts.element.amount') } value={ amount } onChange={ event => setAmount(event.target.value) } />
                        </ContractSection>
                    </div>
                    <ContractSection title={ LocalizeText('wiredcontracts.element.itemtype.selection') } disabled={ type !== WIRED_CONTRACT_FURNI }
                        headerOption={ selected && <span className="wired-contract__selected-icon"><LayoutFurniIconImageView productType={ selected.isWallItem ? FurnitureType.WALL : FurnitureType.FLOOR } productClassId={ selected.typeId } extraData={ selected.legacyPosterId } /></span> }>
                        <label className="wired-contract__named">
                            <ContractText text={ LocalizeText('wiredcontracts.element.itemtype.furni_code') } />
                            <input className="wired-contract__input wired-contract__named-input" type="text" readOnly aria-label={ LocalizeText('wiredcontracts.element.itemtype.furni_code') } placeholder={ LocalizeText('wiredcontracts.element.itemtype.furni_code.placeholder') } value={ selectedCandidate?.code ?? '' } />
                        </label>
                        <label className="wired-contract__named">
                            <ContractText text={ LocalizeText('wiredcontracts.element.itemtype.search') } />
                            <input className="wired-contract__input wired-contract__named-input" type="text" aria-label={ LocalizeText('wiredcontracts.element.itemtype.search') } maxLength={ WIRED_CONTRACT_SEARCH_MAX } value={ query } onChange={ event => { setQuery(event.target.value); setScrollTop(0); } } />
                        </label>
                        <div className="wired-contract__item-table">
                            <ContractSkin type="table" width={ 404 } height={ 234 } />
                            <div className="wired-contract__item-heading">
                                { [ 'furni_name', 'furni_code', 'furni_type' ].map(key => <span key={ key }><ContractText text={ LocalizeText(`wiredcontracts.element.itemtype.col.${ key }`) } bold background={ 0xffffff } /></span>) }
                            </div>
                            <div className="wired-contract__item-scroll" onScroll={ event => setScrollTop(event.currentTarget.scrollTop) }>
                                <div role="listbox" aria-label={ LocalizeText('wiredcontracts.element.itemtype.selection') } style={ { height: filtered.length * ROW_HEIGHT, position: 'relative' } }>
                                    { visible.map((candidate, index) =>
                                        <BaseButton role="option" type="button" key={ wiredContractItemKey(candidate.itemType) } className="wired-contract__item-row"
                                            aria-selected={ wiredContractItemKey(candidate.itemType) === wiredContractItemKey(selected) } data-even={ (first + index) % 2 === 0 }
                                            style={ { top: (first + index) * ROW_HEIGHT } } onClick={ () => setSelected(candidate.itemType) }>
                                            <span>{ candidate.name }</span>
                                            <span>{ candidate.code }</span>
                                            <span>{ LocalizeText(candidate.itemType.isWallItem ? 'inventory.filter.placement.wall' : 'inventory.filter.placement.floor') }</span>
                                        </BaseButton>) }
                                </div>
                            </div>
                        </div>
                        <div className="wired-contract__count"><ContractText text={ LocalizeText('wiredcontracts.element.show_count', [ 'amount' ], [ String(filtered.length) ]) } /></div>
                    </ContractSection>
                </fieldset>
                <ContractFooter saveDisabled={ !canWrite } onSave={ save } onClose={ onClose } />
            </ContractFrame>
        </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