NODE.JS

OnlineShop 만들기 - 6) Landing Page 만들기 3(check 필터링, price 필터링 만들기)

dodop 2021. 5. 15. 22:03

순서

체크한 나라에 관한 (continents) 자료들만 로드되도록 한다.

 

checkbox에 관한 내용들은 sections폴더안에 따로 생성한다. 

src>components>views>LandingPage>Sections>CheckBox.js파일을 생성한다.

import React from 'react'
import { Checkbox, Collapse } from 'antd';


const continents = [
    {
        "_id": 1,
        "name": "Africa"
    },
    {
        "_id": 2,
        "name": "Europe"
    },
    {
        "_id": 3,
        "name": "Asia"
    },
    {
        "_id": 4,
        "name": "North America"
    },
    {
        "_id": 5,
        "name": "South America"
    },
    {
        "_id": 6,
        "name": "Australia"
    },
    {
        "_id": 7,
        "name": "Antarctica"
    }
]

function CheckBox() {
    return (
        <div>
            <Collapse defaultActiveKey={['0']} >
                <Panel header key="1">
                <React.Fragment key={index}>
                <Checkbox
                    onChange
                    type
                    checked
                />
                <span>{value.name}</span>
                </React.Fragment>
                ))                
                </Panel>
            </Collapse>
        </div>
    )
}

 

 

랜딩페이지안에도 넣어준다.

import CheckBox from './Sections/CheckBox';

			{/* Filter  */}

            <CheckBox />

현재상태

 

 

onChange Function을 만들어보자.

import React ,{useState} from 'react'
import { Checkbox, Collapse } from 'antd';



function CheckBox(props) {
    const [Checked, setChecked] = useState([])//어떤걸 체크했는지 배열에 넣어서 알려준다.


    const handleToggle = (value) => {//어떤 체크박스를 넣어줄건지 value를 준다.

        const currentIndex = Checked.indexOf(value);//체크된 것의 인덱스를 가져온다.
        const newChecked = [...Checked]; //체크된것들

        if (currentIndex === -1) {//체크가 안되어 있었으면
            newChecked.push(value)//가져올 checked에 값을 추가한다.
        } else {//이미 체크가 되어있으면
            newChecked.splice(currentIndex, 1)//체크에서 제외해준다.
        }

        setChecked(newChecked)//새로 체크 변화된 것 다시 한번 세팅
        props.handleFilters(newChecked)//변화된것 부모에게 전달해준다. 
        //update this checked information into Parent Component 

    }

    const renderCheckboxLists = () => props.list && props.list.map((value, index) => (
        <React.Fragment key={index}>
            <Checkbox
                onChange={() => handleToggle(value._id)}//체크 표시 
                type="checkbox"
                checked={Checked.indexOf(value._id) === -1 ? false : true}//체크 여부(되지않으면 -1, 되어있으면 !=-1)에 따라서 checked 가 true, false
            />&nbsp;&nbsp;
            <span>{value.name}</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        </React.Fragment>
    ))
    
    
    return (
        <div>
            <Collapse defaultActiveKey={['0']} >
                <Panel header="Continents" key="1">
                    {renderCheckboxLists()}
                </Panel>
            </Collapse>
        </div>
    )
}

여기서 부모에게 전달해줄 handletoggle함수는 부모가 가지고 있어야 하므로 

랜딩페이지에 구현해준다.

순서

 

	 const [Filters, setFilters] = useState({//두가지의 필터를 가지고 있다. 
        continents: [],
        price: []
    })
    
    
    
        const showFilteredResults = (filters) => {//필터링한 결과를 가지고 온다.

        const variables = {
            skip: 0,//체크박스를 새로 설정하면 처음부터 다시 보여줘야 한다.
            limit: Limit,
            filters: filters

        }
        getProducts(variables)//결과를 가져오기 위해서 getProducts사용한다.
        setSkip(0)

    }



    const handleFilters = (filters, category) => {//체크된것들에 변화가 있으면 새로 받아오는 것(자식으로 부터 변화 받아오는 함수 )
        //체크가 된다면 배열 안에 체크된 인덱스 번호가 추가될 것이다. 
        const newFilters = { ...Filters }//새로운 필터만들고

        newFilters[category] = filters//해당카테고리의 필터는 입력된 filters가 될 것이다. 

        if (category === "price") {

        }

        console.log(newFilters)

        //필터링한 결과를 세팅해준다.
        showFilteredResults(newFilters)
        //필터의 상태를 새로운 필터로 바꿔준다.
        setFilters(newFilters)
    }

    
    
    
                {/* Filter  */}    
   					 <CheckBox
                        handleFilters={filters => handleFilters(filters, "continents")}
                    />

getproducts 라우터에서 필터링에 따라서 가져오는 종류가 달라질 수 있도록 수정해준다.

 

router.post("/getProducts", (req, res) => {

    //variables가 있을때와 없을 때를 나눈다.
    let order = req.body.order ? req.body.order : "desc";
    let sortBy = req.body.sortBy ? req.body.sortBy : "_id";
    let limit = req.body.limit ? parseInt(req.body.limit) : 100;
    let skip = parseInt(req.body.skip);

    let findArgs = {};

    for (let key in req.body.filters) { //필터에 따라서 

        if (req.body.filters[key].length > 0) {
            if (key === "price") {
 
                }
            } else {//키가 price가 아니라면
                findArgs[key] = req.body.filters[key];//findArgs[continents] = [인덱스 배열]의 형태
            }
        }
    }


        Product.find(findArgs)
            .populate("writer")
            .sort([[sortBy, order]])
            .skip(skip)
            .limit(limit)
            .exec((err, products) => {
                if (err) return res.status(400).json({ success: false, err })
                res.status(200).json({ success: true, products, postSize: products.length })
            })
    

});

 

 

이제 가격에 의한 필터링을 만들어보자.

순서

체크박스 component처럼 라디오 박스 component를 만들어준다.

src>component>views>Sections>RadioBox.js파일

import React from 'react'
import { Collapse, Radio } from 'antd';
const { Panel } = Collapse;

const price = [
    {
        "_id": 0,
        "name": "Any",
        "array": []
    },
    {
        "_id": 1,
        "name": "$0 to $199",
        "array": [0, 199]
    },
    {
        "_id": 2,
        "name": "$200 to $249",
        "array": [200, 249]
    },
    {
        "_id": 3,
        "name": "$250 to $279",
        "array": [250, 279]
    },
    {
        "_id": 4,
        "name": "$280 to $299",
        "array": [280, 299]
    },
    {
        "_id": 5,
        "name": "More than $300",
        "array": [300, 1500000]
    }
]

function RadioBox() {
    const [Value, setValue] = useState('0')

    const renderRadioBox = () => (
        props.list &&  props.list.map((value) => (
            <Radio key={value._id} value={`${value._id}`}>{value.name}</Radio>
        ))
    )



    return (
        <div>
            <Collapse defaultActiveKey={['0']}>
                <Panel header="price" key="1">
                    <Radio.Group onChange value>

                        {renderRadioBox()}

                    </Radio.Group>
                </Panel>
            </Collapse>
        </div>
    )
}

export default RadioBox

 

랜딩페이지에도 추가해준다.

import RadioBox from './Sections/RadioBox';

            {/* Filter  */}
			<RadioBox
                    handleFilters={filters => handleFilters(filters, "price")}
            
            />

antd를 이용해서 col, row디자인을 준다.

 

 		 {/* Filter  */}

            
            <Row gutter={[16, 16]}>
                <Col lg={12} xs={24} >
                    <CheckBox
                        list={continents}
                        handleFilters={filters => handleFilters(filters, "continents")}
                    />
                </Col>
                <Col lg={12} xs={24}>
                    <RadioBox
                        list={price}
                        handleFilters={filters => handleFilters(filters, "price")}
                    />
                </Col>
            </Row>

 

RadioBox 에 onChange Function을 만들어준다.

    const [Value, setValue] = useState('0')//id가 0부터 시작하니까
    const handleChange = (event) => {
        setValue(event.target.value)
        props.handleFilters(event.target.value)//부모컴포넌트로 보내준다.
    }
    return (
        <div>
            <Collapse defaultActiveKey={['0']}>
                <Panel header="price" key="1">
                    <Radio.Group onChange={handleChange} value={Value}>

                        {renderRadioBox()}

                    </Radio.Group>
                </Panel>
            </Collapse>
        </div>
    )
}

 

 

handleFilter Function을 만들어보자.

순서

 

먼저 가격정보랑 continents 정보를 담았던 CheckBox, RadioBox에서 정보들만 따로 모으자.

Sections>Datas.js파일을 만든다.

const price = [
    {
        "_id": 0,
        "name": "Any",
        "array": []
    },
    {
        "_id": 1,
        "name": "$0 to $199",
        "array": [0, 199]
    },
    {
        "_id": 2,
        "name": "$200 to $249",
        "array": [200, 249]
    },
    {
        "_id": 3,
        "name": "$250 to $279",
        "array": [250, 279]
    },
    {
        "_id": 4,
        "name": "$280 to $299",
        "array": [280, 299]
    },
    {
        "_id": 5,
        "name": "More than $300",
        "array": [300, 1500000]
    }
]




const continents = [
    {
        "_id": 1,
        "name": "Africa"
    },
    {
        "_id": 2,
        "name": "Europe"
    },
    {
        "_id": 3,
        "name": "Asia"
    },
    {
        "_id": 4,
        "name": "North America"
    },
    {
        "_id": 5,
        "name": "South America"
    },
    {
        "_id": 6,
        "name": "Australia"
    },
    {
        "_id": 7,
        "name": "Antarctica"
    }
]


export {
    price, 
    continents
}

랜딩페이지에 둘다 임포트 해준다.

 

import { continents, price } from './Sections/Datas';

 

각각 CheckBox, RadioBox에는 props로 보내주자.

 

            {/* Filter  */}

            <Row gutter={[16, 16]}>
                <Col lg={12} xs={24} >
                    <CheckBox
                        list={continents}//filter보내준다.
                        handleFilters={filters => handleFilters(filters, "continents")}
                    />
                </Col>
                <Col lg={12} xs={24}>
                    <RadioBox
                        list={price}//filter보내준다.
                        handleFilters={filters => handleFilters(filters, "price")}
                    />
                </Col>
            </Row>
//각각 radiobox, checkbox도 props.list로 변경해준다.

	const renderRadioBox = () => (
        props.list &&  props.list.map((value) => (
            <Radio key={value._id} value={`${value._id}`}>{value.name}</Radio>
        ))
    )
    
    
    
    
    const renderCheckboxLists = () => props.list && props.list.map((value, index) => (

 

랜딩페이지에서 handleFilters함수에 다음 내용을 추가한다.

 

    const handlePrice = (value) => {//가격 조정함수
        const data = price;
        let array = [];

        for (let key in data) {//데이터 안의 키들

            if (data[key]._id === parseInt(value, 10)) {// key는 가격이 아니라 인덱스, value는 string으로 되어있는데 이를 int로 바꿔준다.
                array = data[key].array;
            }
        }
        console.log('array', array)
        return array //가격[300, 1500]의 형태
    }

    const handleFilters = (filters, category) => {//체크된것들에 변화가 있으면 새로 받아오는 것(자식으로 부터 변화 받아오는 함수 )
        //체크가 된다면 배열 안에 체크된 인덱스 번호가 추가될 것이다. 
        const newFilters = { ...Filters }//새로운 필터만들고

        newFilters[category] = filters//해당카테고리의 필터는 입력된 filters가 될 것이다. 

        if (category === "price") {//필터카테고리가 가격이라면
            let priceValues = handlePrice(filters)
            newFilters[category] = priceValues//가격범위 지정

        }

        console.log(newFilters)

        //필터링한 결과를 세팅해준다.
        showFilteredResults(newFilters)
        //필터의 상태를 새로운 필터로 바꿔준다.
        setFilters(newFilters)
    }

 

가격조정이라면 route가 다르게 행동하도록 다음과 같이 수정해준다.

    for (let key in req.body.filters) { //필터에 따라서 

        if (req.body.filters[key].length > 0) {
            if (key === "price") {
                findArgs[key] = {
                    $gte: req.body.filters[key][0],//greater than equal
                    $lte: req.body.filters[key][1]//lower than equal
                }
            } else {//키가 price가 아니라면
                findArgs[key] = req.body.filters[key];//findArgs[continents] = [인덱스 배열]의 형태
            }
        }
    }

 

 

 

완성된 화면