5180 fichiers 38.5 Mo 0 téléchargements 297 vues mis à jour il y a 6 heures ui
nitro-v36-with-renderer-v36 / src / components / navigator / views / NavigatorRoomCreatorView.tsx
NavigatorRoomCreatorView.tsx 15.4 Ko Télécharger le fichier
import { CreateFlatMessageComposer } from '@octane/renderer';
import { FC, useMemo, useRef, useState } from 'react';
import { CreateLinkEvent, GetConfigurationValue, IRoomModel, LocalizeText, SendMessageComposer } from '../../../api';
import dropmenuArrow from '../../../assets/images/habbo-skin/slices/dropmenu-default-arrow.png';
import vipIconBig from '../../../assets/images/navigator/air/icon-vip-big.png';
import vipIconSmall from '../../../assets/images/navigator/air/icon-vip-small.png';
import popupArrowDown from '../../../assets/images/navigator/air/popup-arrow-down.png';
import tileIconBlack from '../../../assets/images/navigator/air/tile-icon-black.png';
import tileIconWhite from '../../../assets/images/navigator/air/tile-icon-white.png';
import { DraggableWindow } from '../../../common';
import { useNavigatorData, useNavigatorUiStore, useRoomCreateLimitAlert, useUserDataSnapshot, useUserPermissions } from '../../../hooks';
import { useRoomCreatorStore } from './navigatorRoomCreatorStore';
import { BaseButton } from '../../../common/BaseButton';
import { ListSelect } from '../../../common/ListSelect';
import { ToggleButton } from '../../../common/ToggleButton';
import { NativeTextTree } from '../../../common/native-text/NativeTextTree';

const AIR_TRADE_KEYS = ['navigator.roomsettings.trade_not_allowed', 'navigator.roomsettings.trade_not_with_Controller', 'navigator.roomsettings.trade_allowed'];

const ROOM_LIMIT_HC = 75;
const ROOM_LIMIT_NON_SUBSCRIBER = 50;

const buildVisitorOptions = (limit: number) => {
    const values: string[] = [];

    for (let value = 10; value <= limit; value += 5) values.push(String(value));

    return values;
};

interface RoomCreatorDropmenuProps {
    className: string;
    label: string;
    options: string[];
    value: number;
    onChange: (index: number) => void;
}

const RoomCreatorDropmenu: FC<RoomCreatorDropmenuProps> = (props) => {
    const { className, label, options, value, onChange } = props;
    const [open, setOpen] = useState(false);
    const rootRef = useRef<HTMLDivElement>(null);

    return (
        <NativeTextTree>
            <div ref={rootRef} className={`octane-room-creator-air__dropmenu ${className}${open ? ' is-open' : ''}`}>
                <ListSelect
                    aria-label={label}
                    container={rootRef}
                    itemClassName="octane-room-creator-air__dropmenu-option"
                    options={options.map((option, index) => ({ value: String(index), label: option }))}
                    popupClassName="octane-room-creator-air__dropmenu-list"
                    sideOffset={-1}
                    triggerClassName="octane-room-creator-air__dropmenu-button"
                    value={String(value)}
                    renderTrigger={(current) => (
                        <>
                            <span>{current?.label ?? ''}</span>
                            <img src={dropmenuArrow} alt="" width={16} height={16} />
                        </>
                    )}
                    onOpenChange={setOpen}
                    onValueChange={(next) => onChange(Number(next))}
                />
            </div>
        </NativeTextTree>
    );
};

export const NavigatorRoomCreatorView: FC = () => {
    const { categories } = useNavigatorData();
    const { clubLevel, securityLevel } = useUserDataSnapshot();
    const permissions = useUserPermissions();
    // acc_navigator_staff; a server that sends no keys keeps Flash's staff level (4).
    const isNavigatorStaff = permissions.size ? permissions.get('acc_navigator_staff') === 1 : securityLevel >= 4;
    const beginCreate = useRoomCreatorStore((state) => state.beginCreate);

    const hcDisabled = GetConfigurationValue<boolean>('hc.disabled', false);
    const effectiveClubLevel = hcDisabled ? 2 : clubLevel;

    useRoomCreateLimitAlert(effectiveClubLevel >= 2, () => useRoomCreatorStore.getState().endCreate());

    const [name, setName] = useState('');
    const [nameTouched, setNameTouched] = useState(false);
    const [description, setDescription] = useState('');
    const [descriptionTouched, setDescriptionTouched] = useState(false);
    const [categoryIndex, setCategoryIndex] = useState(0);
    const [visitorsIndex, setVisitorsIndex] = useState(0);
    const [tradeIndex, setTradeIndex] = useState(0);
    const [nameError, setNameError] = useState<string>(null);
    const [roomModels] = useState<IRoomModel[]>(() => GetConfigurationValue<IRoomModel[]>('navigator.room.models') ?? []);
    const [selectedModelName, setSelectedModelName] = useState<string>(() => {
        const models = GetConfigurationValue<IRoomModel[]>('navigator.room.models');

        return models && models.length ? models[0].name : '';
    });

    const visibleModels = useMemo(() => roomModels.filter((model) => model.clubLevel >= 0 || isNavigatorStaff), [roomModels, isNavigatorStaff]);

    const selectableCategories = useMemo(
        () => (categories ?? []).filter((category) => category.visible && !category.automatic && (!category.staffOnly || isNavigatorStaff)),
        [categories, isNavigatorStaff]
    );

    const visitorOptions = useMemo(() => buildVisitorOptions(effectiveClubLevel >= 2 ? ROOM_LIMIT_HC : ROOM_LIMIT_NON_SUBSCRIBER), [effectiveClubLevel]);

    const safeCategoryIndex = categoryIndex < selectableCategories.length ? categoryIndex : 0;
    const safeVisitorsIndex = visitorsIndex < visitorOptions.length ? visitorsIndex : 0;

    const namePlaceholder = LocalizeText('navigator.createroom.roomnameinfo');
    const descriptionPlaceholder = LocalizeText('navigator.createroom.roomdescinfo');
    const tileSizeLabel = LocalizeText('navigator.createroom.tilesize');

    const getRoomModelImage = (modelName: string) => `${GetConfigurationValue<string>('images.url')}/navigator/models/model_${modelName}.png`;

    const closeCreator = () => useNavigatorUiStore.getState().closeCreator();

    const selectModel = (model: IRoomModel) => {
        if (model.clubLevel > 0 && effectiveClubLevel < model.clubLevel) {
            CreateLinkEvent('habboUI/open/hccenter');

            return;
        }

        if (model.clubLevel < 0 && !isNavigatorStaff) return;

        setSelectedModelName(model.name);
    };

    const createRoom = () => {
        const roomName = nameTouched ? name : '';

        if (roomName.trim().length <= 2) {
            setNameError(LocalizeText('navigator.createroom.nameerr'));

            return;
        }

        setNameError(null);

        if (useRoomCreatorStore.getState().isCreating) return;

        beginCreate();

        const category = selectableCategories[safeCategoryIndex];

        SendMessageComposer(
            new CreateFlatMessageComposer(
                roomName,
                descriptionTouched ? description : '',
                `model_${selectedModelName}`,
                category ? category.id : 0,
                Number(visitorOptions[safeVisitorsIndex] ?? 10),
                tradeIndex
            )
        );
    };

    const showVipPromo = effectiveClubLevel < 2 && !hcDisabled;

    return (
        <NativeTextTree>
            <DraggableWindow uniqueKey="navigator-room-creator" handleSelector=".octane-room-creator-air__caption">
                <div className="octane-room-creator-air" data-air-frame="ubuntu-3">
                    <div className="octane-room-creator-air__skin" aria-hidden="true" />
                    <div className="octane-room-creator-air__caption">
                        <span className="octane-room-creator-air__title">{LocalizeText('navigator.createroom.title')}</span>
                        <BaseButton
                            type="button"
                            className="octane-room-creator-air__close"
                            aria-label={LocalizeText('generic.close')}
                            onClick={closeCreator}
                        />
                    </div>

                    <span className="octane-room-creator-air__label octane-room-creator-air__label--name">{LocalizeText('navigator.roomname')}</span>
                    <div className={`octane-room-creator-air__field octane-room-creator-air__field--name${nameError ? ' is-invalid' : ''}`}>
                        <input
                            className="octane-room-creator-air__input"
                            maxLength={25}
                            type="text"
                            value={nameTouched ? name : namePlaceholder}
                            onFocus={() => {
                                if (nameTouched) return;
                                setNameTouched(true);
                                setNameError(null);
                            }}
                            onChange={(event) => setName(event.target.value)}
                        />
                    </div>
                    {nameError && (
                        <div className="octane-room-creator-air__error" role="alert">
                            <div className="octane-room-creator-air__error-border">
                                <span>{nameError}</span>
                            </div>
                            <img className="octane-room-creator-air__error-arrow" src={popupArrowDown} alt="" width={11} height={11} />
                        </div>
                    )}

                    <span className="octane-room-creator-air__label octane-room-creator-air__label--desc">{LocalizeText('navigator.roomdesc')}</span>
                    <div className="octane-room-creator-air__field octane-room-creator-air__field--desc">
                        <textarea
                            className="octane-room-creator-air__input octane-room-creator-air__input--multiline"
                            maxLength={128}
                            value={descriptionTouched ? description : descriptionPlaceholder}
                            onFocus={() => setDescriptionTouched(true)}
                            onChange={(event) => setDescription(event.target.value)}
                        />
                    </div>

                    <span className="octane-room-creator-air__label octane-room-creator-air__label--category">{LocalizeText('navigator.category')}</span>
                    <RoomCreatorDropmenu
                        className="octane-room-creator-air__dropmenu--category"
                        label={LocalizeText('navigator.category')}
                        options={selectableCategories.map((category) => LocalizeText(category.name))}
                        value={safeCategoryIndex}
                        onChange={setCategoryIndex}
                    />

                    <span className="octane-room-creator-air__label octane-room-creator-air__label--visitors">{LocalizeText('navigator.maxvisitors')}</span>
                    <RoomCreatorDropmenu
                        className="octane-room-creator-air__dropmenu--visitors"
                        label={LocalizeText('navigator.maxvisitors')}
                        options={visitorOptions}
                        value={safeVisitorsIndex}
                        onChange={setVisitorsIndex}
                    />

                    <span className="octane-room-creator-air__label octane-room-creator-air__label--trade">{LocalizeText('navigator.tradesettings')}</span>
                    <RoomCreatorDropmenu
                        className="octane-room-creator-air__dropmenu--trade"
                        label={LocalizeText('navigator.tradesettings')}
                        options={AIR_TRADE_KEYS.map((key) => LocalizeText(key))}
                        value={tradeIndex}
                        onChange={setTradeIndex}
                    />

                    <BaseButton type="button" className="octane-room-creator-air__button octane-room-creator-air__button--create" onClick={createRoom}>
                        {LocalizeText('navigator.createroom.create')}
                    </BaseButton>
                    <BaseButton type="button" className="octane-room-creator-air__button octane-room-creator-air__button--cancel" onClick={closeCreator}>
                        {LocalizeText('generic.cancel')}
                    </BaseButton>

                    <span className="octane-room-creator-air__label octane-room-creator-air__label--layout">
                        {LocalizeText('navigator.createroom.chooselayoutcaption')}
                    </span>
                    <div className="octane-room-creator-air__layouts has-classic-scrollbar">
                        <div className="octane-room-creator-air__layout-rows">
                            {visibleModels.map((model) => {
                                const isSelected = selectedModelName === model.name;

                                return (
                                    <ToggleButton
                                        key={model.name}
                                        type="button"
                                        className={`octane-room-creator-air__thumbnail${isSelected ? ' is-selected' : ''}`}
                                        pressed={isSelected}
                                        onClick={() => selectModel(model)}
                                    >
                                        <span className="octane-room-creator-air__thumbnail-bg" aria-hidden="true" />
                                        <img className="octane-room-creator-air__thumbnail-pic" src={getRoomModelImage(model.name)} alt="" />
                                        <img
                                            className="octane-room-creator-air__thumbnail-tile-icon"
                                            src={isSelected ? tileIconWhite : tileIconBlack}
                                            alt=""
                                            width={18}
                                            height={10}
                                        />
                                        <span className="octane-room-creator-air__thumbnail-tiles">
                                            {model.tileSize} {tileSizeLabel}
                                        </span>
                                        {model.clubLevel > 0 && (
                                            <img className="octane-room-creator-air__thumbnail-club" src={vipIconSmall} alt="" width={19} height={10} />
                                        )}
                                    </ToggleButton>
                                );
                            })}
                            {showVipPromo && (
                                <div className="octane-room-creator-air__vip-promo">
                                    <img className="octane-room-creator-air__vip-promo-icon" src={vipIconBig} alt="" width={37} height={37} />
                                    <span className="octane-room-creator-air__vip-promo-text">{LocalizeText('navigator.createroom.vippromo.text')}</span>
                                    <BaseButton
                                        type="button"
                                        className="octane-room-creator-air__vip-promo-link"
                                        onClick={() => CreateLinkEvent('habboUI/open/hccenter')}
                                    >
                                        {LocalizeText('navigator.createroom.vippromo.link')}
                                    </BaseButton>
                                </div>
                            )}
                        </div>
                    </div>
                </div>
            </DraggableWindow>
        </NativeTextTree>
    );
};
15Sujets
1Dépôts
20Membres
2En 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