5180 fichiers 38.5 Mo 0 téléchargements 388 vues mis à jour il y a 7 heures ui
nitro-v36-with-renderer-v36 / src / components / inventory / views / pet / InventoryPetView.tsx
InventoryPetView.tsx 10 Ko Télécharger le fichier
import { InventoryFilterSelect } from '../InventoryFilterSelect';
import { DeletePetMessageComposer, IRoomSession, PetType, RoomPreviewer } from '@octane/renderer';
import { FC, useEffect, useMemo, useState } from 'react';
import { FaTrashAlt } from 'react-icons/fa';
import { attemptPetPlacement, LocalizeText, localizeWithFallback, SendMessageComposer, UnseenItemCategory } from '../../../../api';
import { LayoutRarityLevelView } from '../../../../common';
import { ClassicScrollAreaView } from '../../../../common/scroll-area/ClassicScrollAreaView';
import { useInventoryPets, useInventoryUnseenTracker, useNotification, usePlayTestRestricted } from '../../../../hooks';
import { OctaneButton } from '../../../../layout';
import { InventoryCategoryEmptyView } from '../InventoryCategoryEmptyView';
import { InventoryPetImageView } from './InventoryPetImageView';
import { InventoryPetItemView } from './InventoryPetItemView';
import { BaseButton } from '../../../../common/BaseButton';
import { NativeTextTree } from '../../../../common/native-text/NativeTextTree';

export const InventoryPetView: FC<{
    roomSession: IRoomSession;
    roomPreviewer: RoomPreviewer;
}> = (props) => {
    const { roomSession = null } = props;
    const [isVisible, setIsVisible] = useState(false);
    const { petItems = null, selectedPet = null, setSelectedPet, activate = null, deactivate = null } = useInventoryPets();
    const { isUnseen = null, removeUnseen = null } = useInventoryUnseenTracker();
    const { showConfirm = null } = useNotification();
    const playTestRestricted = usePlayTestRestricted();

    const [searchInput, setSearchInput] = useState('');
    const [search, setSearch] = useState('');
    const [typeFilter, setTypeFilter] = useState(-1);
    const availableTypes = useMemo(() => [...new Set((petItems ?? []).map(({ petData }) => petData.typeId))].sort((a, b) => a - b), [petItems]);
    const activeType = availableTypes.includes(typeFilter) ? typeFilter : -1;
    // Like the official client, only monster plants can be filtered by rarity.
    const [rarityFilter, setRarityFilter] = useState(-1);
    const rarityFilterEnabled = activeType === PetType.MONSTERPLANT;
    const availableRarities = useMemo(
        () =>
            [
                ...new Set(
                    (petItems ?? []).filter(({ petData }) => petData.typeId === PetType.MONSTERPLANT && petData.rarityLevel >= 0).map(({ petData }) => petData.rarityLevel)
                )
            ].sort((a, b) => a - b),
        [petItems]
    );
    const activeRarity = rarityFilterEnabled && availableRarities.includes(rarityFilter) ? rarityFilter : -1;
    const visiblePets = useMemo(
        () =>
            (petItems ?? []).filter(
                ({ petData }) =>
                    (activeType === -1 || petData.typeId === activeType) &&
                    (activeRarity === -1 || petData.rarityLevel === activeRarity) &&
                    (!search || petData.name.toLowerCase().includes(search) || LocalizeText(`pet.type.${petData.typeId}`).toLowerCase().includes(search))
            ),
        [petItems, activeType, activeRarity, search]
    );

    useEffect(() => {
        if (!visiblePets.includes(selectedPet)) setSelectedPet(visiblePets[0] ?? null);
    }, [visiblePets, selectedPet, setSelectedPet]);

    const attemptDeletePet = () => {
        if (!selectedPet?.petData) return;

        showConfirm(
            localizeWithFallback(
                'inventory.delete.confirm_delete.info',
                `Delete ${selectedPet.petData.name}?`,
                ['furniname', 'amount'],
                [selectedPet.petData.name, '1']
            ),
            () => SendMessageComposer(new DeletePetMessageComposer(selectedPet.petData.id)),
            null,
            null,
            null,
            localizeWithFallback('inventory.delete.confirm_delete.title', 'Delete pet')
        );
    };

    useEffect(() => {
        if (!selectedPet || !isUnseen(UnseenItemCategory.PET, selectedPet.petData.id)) return;
        removeUnseen(UnseenItemCategory.PET, selectedPet.petData.id);
    }, [selectedPet, isUnseen, removeUnseen]);

    useEffect(() => {
        if (!isVisible) return;
        const id = activate();
        return () => deactivate(id);
    }, [isVisible, activate, deactivate]);

    useEffect(() => {
        setIsVisible(true);
        return () => setIsVisible(false);
    }, []);

    if (!petItems || !petItems.length) {
        return <InventoryCategoryEmptyView desc={LocalizeText('inventory.empty.pets.desc')} title={LocalizeText('inventory.empty.pets.title')} />;
    }

    return (
        <NativeTextTree>
            <div className="octane-inventory-animals is-pets">
                <div className="octane-inventory-filter-bar">
                    <div className="octane-inventory-filter-search">
                        <input
                            className="octane-inventory-filter-input"
                            aria-label={LocalizeText('generic.search')}
                            value={searchInput}
                            onChange={(event) => setSearchInput(event.target.value)}
                            onKeyDown={(event) => {
                                if (event.key === 'Enter') setSearch(searchInput.toLowerCase());
                                if (event.key === 'Escape') {
                                    setSearchInput('');
                                    setSearch('');
                                }
                            }}
                        />
                        {searchInput && (
                            <BaseButton
                                type="button"
                                className="octane-inventory-filter-clear"
                                aria-label={LocalizeText('generic.clear')}
                                onClick={() => {
                                    setSearchInput('');
                                    setSearch('');
                                }}
                            />
                        )}
                    </div>
                    <InventoryFilterSelect
                        aria-label="Pet type"
                        value={activeType}
                        onChange={(value) => {
                            setTypeFilter(Number(value));
                            setSearch(searchInput.toLowerCase());
                        }}
                    >
                        <option value={-1}>
                            {LocalizeText('inventory.pets.filter.type.all') === 'inventory.pets.filter.type.all'
                                ? 'All types'
                                : LocalizeText('inventory.pets.filter.type.all')}
                        </option>
                        {availableTypes.map((type) => (
                            <option key={type} value={type}>
                                {LocalizeText(`pet.type.${type}`)}
                            </option>
                        ))}
                    </InventoryFilterSelect>
                    <InventoryFilterSelect
                        aria-label="Pet rarity"
                        disabled={!rarityFilterEnabled}
                        value={activeRarity}
                        onChange={(value) => setRarityFilter(Number(value))}
                    >
                        <option value={-1}>
                            {LocalizeText('inventory.pets.filter.rarity.all') === 'inventory.pets.filter.rarity.all'
                                ? 'All rarities'
                                : LocalizeText('inventory.pets.filter.rarity.all')}
                        </option>
                        {rarityFilterEnabled &&
                            availableRarities.map((rarity) => (
                                <option key={rarity} value={rarity}>
                                    {rarity}
                                </option>
                            ))}
                    </InventoryFilterSelect>
                </div>
                <div className="octane-inventory-animal-grid">
                    <ClassicScrollAreaView className="size-full">
                        <div className="octane-inventory-animal-cells">
                            {visiblePets.map((item) => (
                                <InventoryPetItemView key={item.petData.id} petItem={item} />
                            ))}
                        </div>
                    </ClassicScrollAreaView>
                </div>
                <div className="octane-inventory-animal-preview">
                    <div className="octane-inventory-animal-name">{selectedPet?.petData.name}</div>
                    <div className="octane-inventory-animal-image">{selectedPet && <InventoryPetImageView pet={selectedPet.petData} preview />}</div>
                    {selectedPet?.petData.rarityLevel >= 0 && (
                        <LayoutRarityLevelView className="octane-inventory-animal-preview-rarity" level={selectedPet.petData.rarityLevel} />
                    )}
                    <div className="octane-inventory-animal-description">{selectedPet && LocalizeText(`pet.type.${selectedPet.petData.typeId}`)}</div>
                    <div className="octane-inventory-animal-actions">
                        <OctaneButton
                            className="octane-inventory-animal-place"
                            disabled={!selectedPet || !(roomSession?.isRoomOwner || roomSession?.allowPets) || playTestRestricted}
                            onClick={() => attemptPetPlacement(selectedPet)}
                        >
                            {LocalizeText('inventory.pets.placetoroom')}
                        </OctaneButton>
                        <OctaneButton className="octane-inventory-btn-delete" disabled={!selectedPet} onClick={attemptDeletePet}>
                            <FaTrashAlt className="fa-icon" />
                            <span>{LocalizeText('generic.delete')}</span>
                        </OctaneButton>
                    </div>
                </div>
            </div>
        </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