Как добавить определенный объект, если объект содержит значение?

#javascript #reactjs #react-redux #lodash

Вопрос:

У меня есть такая страница, как эта, см. страницу

Он выполняет фильтрацию и все такое. Но, тем не менее, я хочу добавить уровень под названием «Верхний базовый» к каждому языку, если язык:

  • Японский
  • Немецкий
  • Голландский
  • Итальянская
  • Арабский
  • Китайский
  • Русский
  • Испанский
  • Французский
  • Корейский

Мой код для этой страницы таков:

 import React from 'react';
import NavigationWithCart from '../../components/navbar/Navigation';
import _, { result } from 'lodash';
import {
    Box,
    Heading,
    Text,
    Grid,
    Button,
    Select,
    Icon,
    Divider,
    Badge,
    Flex,
    Stack
} from '@chakra-ui/react';
import './ChooseClass.css';
import {
    ArrowBackIcon,
    ArrowForwardIcon
} from '@chakra-ui/icons';
import 'tachyons';
import LANGUAGEIMG from '../../images/choose-language-img/ChooseClassImg';
import {
    BiCalendarEdit,
    BiUser
} from 'react-icons/bi';
import './ChooseClass.css';
import { store } from '../..';
import { connect } from 'react-redux';
import TYPES from './Objects/TYPES';
import LEVELS from './Objects/LEVELS';
import { filterLanguage, filterType, filterLevel, selectClass, removeClass } from '../../redux/actions';


// document.getElementsByClassName('css-1ro341c')[0]
const mapStateToProps = state => {
    return {
        selectedLanguage: state.shoppingProcess.selectedLanguage,
        selectedLevel: state.shoppingProcess.selectedLevel,
        filteredLanguage: state.filterItems.language,
        filteredType: state.filterItems.type,
        filteredLevel: state.filterItems.level
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        onFilterLanguage: (e) => dispatch(filterLanguage(e.target.value)),
        onFilterType: (e) => dispatch(filterType(e.target.value)),
        onFilterLevel: (e) => dispatch(filterLevel(e.target.value)),
        onSelectClass: (e) => {
            let oldSelected = document.getElementsByClassName('select-class shadow-5');
            if (oldSelected.length !== 0) {
                oldSelected[0].classList.remove('shadow-5');
                dispatch(selectClass(JSON.parse(e.target.dataset.json)));
                e.target.classList.add('shadow-5');
            } else {
                console.log('none');
                dispatch(selectClass(JSON.parse(e.target.dataset.json)));
                e.target.classList.add('shadow-5');
            }
        },
        onDeleteClass: () => dispatch(removeClass())
    }
}


class ChooseClass extends React.Component{
     componentDidMount(){
        this.props.onDeleteClass();
    }


    render(){
        const FilterLanguageItems = () => {
            return (
                LANGUAGEIMG.filter(item => item.value !== this.props.selectedLanguage).map(filteredItem => (
                <option key={filteredItem.value} value={filteredItem.value}>{capitalizeFirstLetter(filteredItem.value) ' ' countryToFlag(filteredItem.code)}</option>
            )))
        }
        const FilterTypeItems = () => {
            return (
                TYPES.map(item => (
                <option key={item.value} value={item.value}>{item.value}</option>
            )))
        }
        const FilterLevelItems = () => {
            return (
                LEVELS.map(item => (
                    <option key={item.value} value={item.value}>{item.value}</option>      
                )
            ))
        }

        function capitalizeFirstLetter(string) {
            return string.charAt(0).toUpperCase()   string.slice(1);
        }
        function countryToFlag(isoCode) {
            return typeof String.fromCodePoint !== 'undefined'
              ? isoCode
                  .toUpperCase()
                  .replace(/./g, (char) => String.fromCodePoint(char.charCodeAt(0)   127397))
              : isoCode;
          }
        const LanguageBox = () => {
            let languageIsFiltered = store.getState().filterItems.language;
            let selectedLang = languageIsFiltered?languageIsFiltered:store.getState().shoppingProcess.selectedLanguage;
            let filteredType = store.getState().filterItems.type;
            let filteredLevel = store.getState().filterItems.level;
            return (
                LEVELS.filter(item => filteredLevel === 'All'?item.value !== 'All':item.value !== 'All' amp;amp; item.value.includes(filteredLevel)).map((filteredLevel) => (
                TYPES.filter(item => filteredType === 'All'?item.value !== 'All':item.value !== 'All' amp;amp; item.value.includes(filteredType)).map((filteredType) => (
                LANGUAGEIMG.filter(item => item.value.includes(selectedLang)).map((searchedItem) => {
                    const rows = [];
                    rows.push(searchedItem, filteredType, filteredLevel);
                    console.log(rows);
                    return (
                    <Stack key={searchedItem.value} mt={5} maxW={'352px'} display="grid" placeItems="center">
                        <Box cursor="pointer!important" onClick={this.props.onSelectClass} className="select-class" data-json={'{"language": "' capitalizeFirstLetter(searchedItem.value) '" , "type": "' filteredType.value '", "level": "' filteredLevel.value '"}'} display="grid" borderRadius="20px" position="relative" key={searchedItem.value} w="100%" h="auto">
                            {searchedItem.label}<Badge borderRadius="10px" p={1} pr={2} pl={2} m={3} position="absolute" color="white" backgroundColor={filteredLevel.color}>{filteredLevel.value}</Badge>
                        </Box>
                        <Flex pointerEvents="none" mt={'0px!important'} alignItems='center' direction="row" w="100%" justifyContent="space-between">
                            <Box w="15%" fontSize="46px">
                                {countryToFlag(searchedItem.code)}
                            </Box>
                            <Box w="35%" pl={2}>
                                <Text textColor="#23262F" w="100%" fontFamily="Plus Jakarta Sans" fontSize="16px" fontWeight={600}>
                                    {capitalizeFirstLetter(searchedItem.value)}
                                </Text>
                                <Text textColor="#777E90" fontFamily="Eudoxus Sans" fontWeight={500} fontSize='14px'>
                                    {filteredType.value}
                                </Text>
                            </Box>
                            <Box w="50%">
                                <Text p={1} display="flex" justifyContent="flex-end" fontFamily="Plus Jakarta Sans" fontSize="18px" textTransform="uppercase" textColor="#009A9D">
                                    Rp 120.000
                                </Text>
                            </Box>
                        </Flex>
                        <Divider pointerEvents="none" mt={'0!important'}/>
                        <Flex pointerEvents="none" dir="column" w="100%">
                            <Box w="100%" fontSize="12px" fontFamily="Plus Jakarta Sans" textColor="#353945">
                                <Icon mr={2} as={BiCalendarEdit} w="20px" h="auto" color="#353945"/>
                                25/05/2021
                            </Box>
                            <Box textColor="#353945" fontSize="12px" fontFamily="Plus Jakarta Sans" w="100%" display="flex" justifyContent="flex-end">
                                <Icon mr={2} color="#353945" as={BiUser} w="20px" h="auto"/>
                                160 slots
                            </Box>
                        </Flex>
                    </Stack>
                )})
            ))
            ))
            )
        }
        return (
            
            <Box width="100%" display={{base: 'block', sm: 'block', md: 'block', lg: 'grid'}} placeItems="center">
                <Box w="97%" display="grid" placeItems="center" m={{base: 0, sm: 0, md: 0, lg: 2}}>
                    <NavigationWithCart
                    val="50%"
                    />
                </Box>
                <Box w={{base: '100%', sm: '100%', md: '100%', lg: "98%"}} p={{base: 1, sm: 1, md: 1, lg:10}} h="100%!important" display="grid" placeItems="center"> 
                    <Box w={{base: "90%", sm: "90%", md: '90%', lg: "60%"}}>
                        <Box w="100%">
                            <Button onClick={() => window.location.replace('/choose-language')} borderRadius={'20px'} colorScheme="teal" variant="outline" w={'180px'} fontSize={'13px'}>
                                <Icon as={ArrowBackIcon} mr={2} w="18px" h="auto" />
                                Back to Language
                            </Button>                
                        </Box>
                        <Box w="100%" mt={{base: 5, sm: 5, md: 5, lg: 'unset'}} textAlign="center">
                            <Heading color="teal" fontWeight={600} textColor="#009A9D" fontFamily="Plus Jakarta Sans">
                                Choose your class
                            </Heading>
                        </Box>
                        <Divider m={1} mt={4}/>
                        <Flex w="100%" direction={{base: 'column', sm: 'column', md: 'column', lg:"row"}}>
                            <Box w="100%" mt={{base: 3, sm: 3, md: 3, lg: 0}} m={{base: 0, sm: 0, md: 0, lg: 3}} mb={{base: 3, sm: 3, md: 1, lg: 3}}>
                                <Text opacity="60%" fontWeight='bold' fontFamily='Plus Jakarta Sans' fontSize="14px">
                                    LANGUAGE
                                </Text>
                                <Select onChange={this.props.onFilterLanguage} value={this.props.filteredLanguage?this.props.filteredLanguage:this.props.selectedLanguage} placeholder={capitalizeFirstLetter(this.props.selectedLanguage)} mt={2} borderRadius="12px">
                                    <FilterLanguageItems/>
                                </Select>
                            </Box>
                            <Box  w="100%" m={{base: 0, sm: 0, md: 0, lg: 3}} mb={{base: 3, sm: 3, md: 1, lg: 3}}>
                                <Text opacity="60%" fontWeight='bold' fontFamily='Plus Jakarta Sans' fontSize="14px">
                                    TYPE
                                </Text>
                                <Select onChange={this.props.onFilterType} mt={2} borderRadius="12px" value={this.props.filteredType?this.props.filteredType:this.props.filteredType[0]}>
                                    <FilterTypeItems/>
                                </Select>
                            </Box>
                            <Box w="100%" m={{base: 0, sm: 0, md: 0, lg: 3}} mb={{base: 3, sm: 3, md: 1, lg: 3}}>
                                <Text opacity="60%" fontWeight='bold' fontFamily='Plus Jakarta Sans' fontSize="14px">
                                    LEVEL
                                </Text>
                                <Select onChange={this.props.onFilterLevel}  mt={2} borderRadius="12px" value={this.props.filteredLevel?this.props.filteredLevel:this.props.filteredLevel[0]}>
                                    <FilterLevelItems/>
                                </Select>
                            </Box>
                            <Box w="100%" m={{base: 0, sm: 0, md: 0, lg: 3}} mb={{base: 3, sm: 3, md: 1, lg: 3}}>
                                <Text visibility="hidden" opacity="60%" fontWeight='bold' fontFamily='Plus Jakarta Sans' fontSize="14px">
                                    LANGUAGE
                                </Text>
                                <Button w="100%" rightIcon={<ArrowForwardIcon />} mt={2} justifyContent="space-between" borderRadius={12} colorScheme="teal" background="#009A9D" textAlign="start" variant="solid">
                                    Next
                                </Button>
                            </Box>
                        </Flex>
                        <Grid templateColumns={{base: "repeat(1, 1fr)", sm: "repeat(1, 1fr)", md: "repeat(3, 1fr)"}} gap={10}>
                            <LanguageBox/>
                        </Grid>
                    </Box>
                </Box>
            </Box>
        )
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(ChooseClass);
 

LANGUAGEIMG.js:

 const LANGUAGEIMG = [
    {code: 'EG', value: 'egyptian', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./ANCIENT-EGYPT.png').default} /></div> },
    {code: 'SA', value: 'arabic', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./ARABIC.png').default} /></div> },
    {code: 'ID', value: 'batak', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./BATAK.png').default} /></div> },
    {code: 'CN', value: 'chinese', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./CHINA.png').default} /></div> },
    {code: 'NL', value: 'dutch', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./DUTCH.png').default} /></div>},
    {code: 'GB', value: 'english', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./ENG-CONVO.png').default} /></div>},
    {code: 'ES', value: 'esperanto', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./ESPERANTO.png').default} /></div>},
    {code: 'GF', value: 'french', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./FRENCE.png').default} /></div> },
    {code: 'DE', value: 'german', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./GERMAN.png').default} /></div> },
    {code: 'IL', value: 'hebrew', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./HEBREW.png').default} /></div> },
    {code: 'HU', value: 'hungarian', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./HUNGARIAN.png').default} /></div>},
    {code: 'IN', value: 'india', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./INDIA.png').default} /></div>},
    {code: 'ID', value: 'indonesia', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./INDONESIA.png').default} /></div>},
    {code: 'IT', value: 'italian', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./ITALIAN.png').default} /></div> },
    {code: 'JP', value: 'japanese', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./JAPANESE.png').default} /></div> },
    {code: 'ID', value: 'jawa', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./JAWA.png').default} /></div> },
    {code: 'KR', value: 'korean', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./KOREAN.png').default} /></div>},
    {code: 'ID', value: 'madura', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./MADURA.png').default} /></div>},
    {code: 'NO', value: 'norwegian', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./NORWEGIAN.png').default} /></div>},
    {code: 'IR', value: 'persian', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./PERSIAN.png').default} /></div> },
    {code: 'PL', value: 'polish', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./POLISH.png').default} /></div> },
    {code: 'PT', value: 'portuguese', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./PORTUGUESE.png').default} /></div> },
    {code: 'RU', value: 'russian', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./RUSSIAN.png').default} /></div>},
    {code: 'SIGN', value: 'sign-language', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./SIGN-LANG.png').default} /></div>},
    {code: 'ES', value: 'spanish', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./SPANISH.png').default} /></div>},
    {code: 'ID', value: 'sunda', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./SUNDA.png').default} /></div> },
    {code: 'NE', value: 'swahili', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./SWAHILI.png').default} /></div> },
    {code: 'SE', value: 'swedish', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./SWEDEN.png').default} /></div>},
    {code: 'PH', value: 'tagalog', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./TAGALOG.png').default} /></div> },
    {code: 'TH', value: 'thai', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./THAI.png').default} /></div> },
    {code: 'TR', value: 'turkish', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./TURKISH.png').default} /></div> },
    {code: 'PK', value: 'urdu', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./URDU.png').default} /></div> },
    {code: 'VN', value: 'vietnamese', label: <div style={{pointerEvents: 'none'}}><img alt=""style={{pointerEvents: 'none', objectFit: 'cover', width: '352px', height: '275px', borderRadius: '18px'}} src={require('./VIETNAM.png').default} /></div> },
]

export default LANGUAGEIMG;
 

LEVELS.js:

 const LEVELS = [
    { value: 'All', color: 'none' },
    { value: 'Beginner', color: '#009A9D' },
    // the value i want to add
    // { value: 'Upper Basic', color: 'green' },
    ///
    { value: 'Intermediate', color: '#CB31D8' },
    { value: 'Advanced', color: '#FE7A55' },   
]

export default LEVELS;
 

TYPES.js:

 const TYPES = [
    {value: 'All'},
    {value: 'Basic'},
    {value: 'Private'},
    {value: 'ETP (TOEFL)'},
    {value: 'ETP (IELTS)'}
]

export default TYPES;
 

Пожалуйста, помогите мне, спасибо

Ответ №1:

Вы можете сделать что-то подобное:

 const LEVELS = [
    { value: 'All', color: 'none' },
    { value: 'Beginner', color: '#009A9D' },
    { value: 'Upper Basic', color: 'green', langs: ['Japanese', 'German' /* and so on */] },
    { value: 'Intermediate', color: '#CB31D8' },
    { value: 'Advanced', color: '#FE7A55' },   
];

const FilterLevelItems = () => {
    return LEVELS
        .filter(item => !item.langs || item.langs.includes(this.props.selectedLanguage))
        .map(item => <option key={item.value} value={item.value}>{item.value}</option>);
};
 

Комментарии:

1. Извините, куда мне поместить эту функцию?

2. где вы положили его раньше — внутри ChooseClass компонента