学生向けプログラミング入門 | 無料

学生向けにプログラミングを無料で解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails, Python, Django

Django3.2 | 33 | QRオーダーシステムの構築 | カート実装

[32 | カートボタン] << [ホーム] >> [34 | Stripeモデルの実装]

「qrmenu_react/src/components」フォルダに「ShoppingCart.js」ファイルを新規作成します。
作成した「src/components/ShoppingCart.js」ファイルを以下のように編集します。



新規作成 【QRMenu/qrmenu_react/src/components/ShoppingCart.js】

import React, {useMemo } from 'react';
import { Card } from 'react-bootstrap';

const ShoppingCart = ({ items }) => {
    const totalPrice = useMemo(
        () => items.map((i) => i.quantity * i.price).reduce((a,b) => a+b, 0),
        [items]
    );

    return (
        <>
            <h3 className="text-center mb-4">
                <b>注文内容</b>
            </h3>
            <Card>
                <Card.Body>
                    {totalPrice}
                </Card.Body>
            </Card>
        
        
        </>
    );
}

export default ShoppingCart;



「src/pages/Menu.js」ファイルを編集します。


記述編集 【QRMenu/qrmenu_react/src/pages/Menu.js】

import { Container, Row, Col, Button } from 'react-bootstrap';
import { IoCloseOutline } from 'react-icons/io5';
import { useParams } from 'react-router-dom';
import React, { useState, useEffect, useMemo } from 'react';
import { fetchPlace } from '../apis';
import styled from 'styled-components';

import MenuList from '../components/MenuList';
import ShoppingCart from '../components/ShoppingCart';

const OrderButton = styled(Button)`
    position: fixed;
    bottom: 20px;
    right: 20px;
    border-radius: 50%;
    box-shadow: 1px 1px 8px rgba(0,0,0,0.2);
    width: 80px;
    height: 80px;

    }
`;

const Menu = () => {
    const [ place, setPlace ] = useState({});
    const [shoppingCart, setShoppingCart] = useState({});
    const [showShoppingCart, setShowShoppingCart] = useState(false);

    const params = useParams();

    const onFetchPlace = async () => {
        const json = await fetchPlace(params.id);
        console.log(json);
        if(json) {
            setPlace(json);
        }
    };

    const onAddItemtoShoppingCart = (item) => {
        setShoppingCart({
            ...shoppingCart,
            [item.id]:{
                ...item,
                quantity: (shoppingCart[item.id]?.quantity || 0) + 1,
            }
        });
    }

    const totalQuantity = useMemo(
        () => Object.keys(shoppingCart)
            .map((i) => shoppingCart[i].quantity)
            .reduce((a,b) => a+ b, 0),
            [shoppingCart]
    );

    useEffect(() => {
        onFetchPlace();
    }, []);

    return (
        <Container ClassName="mt-5 mb-5">
            <Row className="justify-content-center">
                <Col lg={8}>
                    {showShoppingCart ? (
                        <ShoppingCart 
                            items={Object.keys(shoppingCart)
                            .map((key) => shoppingCart[key])
                            .filter((item) => item.quantity > 0)
                            }
                        />
                    ) : (
                        <MenuList 
                            place={place} 
                            shoppingCart={shoppingCart} 
                            onOrder={onAddItemtoShoppingCart} 
                        />
                    )}

                </Col>
            </Row>

            {totalQuantity ? (
                <OrderButton variant="standard" onClick={() => setShowShoppingCart(!showShoppingCart)}>
                    <div Style="font-size: 13px;">注文確定</div>
                    {showShoppingCart ? <IoCloseOutline size={25} /> : totalQuantity}
                </OrderButton>
            ) : null}
        </Container>
    )
};

export default Menu;



注文確定ボタンを押すと、合計金額が出るようになりました。

合計金額表示
合計金額表示



「src/components/ShoppingCart.js」ファイルを以下のように追加編集します。


追加編集 【QRMenu/qrmenu_react/src/components/ShoppingCart.js】

import React, {useMemo } from 'react';
import { Card } from 'react-bootstrap';

const ShoppingCart = ({ items }) => {
    const totalPrice = useMemo(
        () => items.map((i) => i.quantity * i.price).reduce((a,b) => a+b, 0),
        [items]
    );

    return (
        <>
            <h3 className="text-center mb-4">
                <b>注文内容</b>
            </h3>
            <Card>
                <Card.Body>
                    {items.map((item) => (
                        <div key={item.id} className="d-flex mb-4 align-items-center">
                            <div className="flex-grow-1">
                                <p className="mb-0">
                                    <b>{item.name}</b>
                                </p>
                                <span>{item.price}円</span>    
                            </div>

                            <div className="d-flex align-items-center">
                                <span>{item.quantity}</span>
                            </div>
                        </div>
                    ))}

                    <hr/>
                    <div className="d-flex justify-content-between">
                        <h6><b>合計金額</b></h6>
                        <h5><b>{totalPrice.toLocaleString()}円</b></h5>
                    </div>
                </Card.Body>
            </Card>
        
        
        </>
    );
}

export default ShoppingCart;



合計金額が表示されるようになりました。

合計金額表示
合計金額表示



「src/components」フォルダに「OperationButton.js」ファイルを新規作成します。
作成した「OperationButton.js」ファイルを以下のように編集します。



新規作成 【QRMenu/qrmenu_react/src/components/OperationButton.js】

import { Button } from 'react-bootstrap';
import styled from 'styled-components';

const OperationButton = styled(Button)`
    width: 30px;
    height: 30px;
    margin: 0 10px;
    font-size: 20px;
    line-height: 18px;
`;

export default OperationButton;



「src/components/QRCodeModal.js」ファイルを編集します。


記述編集 【QRMenu/qrmenu_react/src/components/QRCodeModal.js】

import React from 'react';
import { Modal, Container, Row, Col, Button } from 'react-bootstrap';
import { AiFillPlusCircle, AiFillMinusCircle } from 'react-icons/ai';
import QRCode from './QRCode';
import OperationButton from './OperationButton';


const QRCodeModal = ({ show, onHide, place, onUpdatePlace }) => (
    <Modal show={show} onHide={onHide} size="lg" centered>
        <Modal.Body className="text-center pt-4">
            <Container>
                <h3>客席 QRコード</h3>
                <div className="s-flex align-items-center mt-4 mb-4">
                    <h5 className="mb-0 mr-2">
                        全席数: <b>{place.number_of_tables}</b>
                    </h5>

                    <OperationButton 
                        variant="lightgray"
                        size="sm"
                        onClick={() => onUpdatePlace(place.number_of_tables -1)}
                    >
                        <AiFillMinusCircle size={25} color="red" />
                    </OperationButton>
                    <OperationButton 
                        variant="lightgray"
                        size="sm"
                        onClick={() => onUpdatePlace(place.number_of_tables +1)}
                    >
                        <AiFillPlusCircle size={25} color="blue" />
                    </OperationButton>
                </div>
                <Row>
                    {Array.from({ length: place.number_of_tables }, (_, i) => i + 1).map(
                        (table) => (
                            <Col key={table} lg={4} md={6} className="mb-4">
                                <QRCode table={table} placeId={place.id} />
                            </Col>
                        )    
                    )}
                </Row>
            </Container>
        </Modal.Body>
    </Modal>
)

export default QRCodeModal;



「src/components/ShoppingCart.js」ファイルを編集します。


記述編集 【Desktop/QRMenu/qrmenu_react/src/components/ShoppingCart.js】

import React, {useMemo } from 'react';
import { Card } from 'react-bootstrap';
import OperationButton from './OperationButton';
import { AiFillPlusCircle, AiFillMinusCircle } from 'react-icons/ai';

const ShoppingCart = ({ items, onAdd, onRemove }) => {
    const totalPrice = useMemo(
        () => items.map((i) => i.quantity * i.price).reduce((a,b) => a+b, 0),
        [items]
    );

    return (
        <>
            <h3 className="text-center mb-4 mt-5">
                <b>注文内容</b>
            </h3>
            <Card>
                <Card.Body>
                    {items.map((item) => (
                        <div key={item.id} className="d-flex mb-4 align-items-center">
                            <div className="flex-grow-1">
                                <p className="mb-0">
                                    <b>{item.name}</b>
                                </p>
                                <span>{item.price}円</span>    
                            </div>

                            <div className="d-flex align-items-center">
                                <OperationButton
                                    variant="lightgray"
                                    size="sm"
                                    onClick={() => onRemove(item)}
                                >
                                    <AiFillMinusCircle size={25} color="red" />
                                </OperationButton>
                                <span>&nbsp;&nbsp;{item.quantity}</span>
                                <OperationButton
                                    variant="lightgray"
                                    size="sm"
                                    onClick={() => onAdd(item)}
                                >
                                    <AiFillPlusCircle size={25} color="blue" />
                                </OperationButton>
                            </div>
                        </div>
                    ))}

                    <hr/>
                    <div className="d-flex justify-content-between">
                        <h6><b>合計金額</b></h6>
                        <h5><b>{totalPrice.toLocaleString()}円</b></h5>
                    </div>
                </Card.Body>
            </Card>
        
        
        </>
    );
}

export default ShoppingCart;



「src/pages/Menu.js」ファイルを編集します。


記述編集 【QRMenu/qrmenu_react/src/pages/Menu.js】

import { Container, Row, Col, Button } from 'react-bootstrap';
import { IoCloseOutline } from 'react-icons/io5';
import { useParams } from 'react-router-dom';
import React, { useState, useEffect, useMemo } from 'react';
import { fetchPlace } from '../apis';
import styled from 'styled-components';

import MenuList from '../components/MenuList';
import ShoppingCart from '../components/ShoppingCart';

const OrderButton = styled(Button)`
    position: fixed;
    bottom: 20px;
    right: 20px;
    border-radius: 50%;
    box-shadow: 1px 1px 8px rgba(0,0,0,0.2);
    width: 80px;
    height: 80px;

    }
`;

const Menu = () => {
    const [ place, setPlace ] = useState({});
    const [shoppingCart, setShoppingCart] = useState({});
    const [showShoppingCart, setShowShoppingCart] = useState(false);

    const params = useParams();

    const onFetchPlace = async () => {
        const json = await fetchPlace(params.id);
        console.log(json);
        if(json) {
            setPlace(json);
        }
    };

    const onAddItemtoShoppingCart = (item) => {
        setShoppingCart({
            ...shoppingCart,
            [item.id]:{
                ...item,
                quantity: (shoppingCart[item.id]?.quantity || 0) + 1,
            }
        });
    }

    const onRemoveItemToShoppingCart = (item) => {
        if(totalQuantity === 1) {
            setShowShoppingCart(false);
        }
        setShoppingCart({
            ...shoppingCart,
            [item.id]:{
                ...item,
                quantity: (shoppingCart[item.id]?.quantity || 0) - 1,
            }
        });
    }


    const totalQuantity = useMemo(
        () => Object.keys(shoppingCart)
            .map((i) => shoppingCart[i].quantity)
            .reduce((a,b) => a+ b, 0),
            [shoppingCart]
    );

    useEffect(() => {
        onFetchPlace();
    }, []);

    return (
        <Container ClassName="mt-5 mb-5">
            <Row className="justify-content-center">
                <Col lg={8}>
                    {showShoppingCart ? (
                        <ShoppingCart 
                            items={Object.keys(shoppingCart)
                            .map((key) => shoppingCart[key])
                            .filter((item) => item.quantity > 0)
                            }
                            onAdd={onAddItemtoShoppingCart}
                            onRemove={onRemoveItemToShoppingCart}
                        />
                    ) : (
                        <MenuList 
                            place={place} 
                            shoppingCart={shoppingCart} 
                            onOrder={onAddItemtoShoppingCart} 
                        />
                    )}

                </Col>
            </Row>

            {totalQuantity ? (
                <OrderButton variant="standard" onClick={() => setShowShoppingCart(!showShoppingCart)}>
                    <div Style="font-size: 13px;">注文確定</div>
                    {showShoppingCart ? <IoCloseOutline size={25} /> : totalQuantity}
                </OrderButton>
            ) : null}
        </Container>
    )
};

export default Menu;



アイテム数の増減ができるようになりました。

アイテム数の増減
アイテム数の増減



↓↓クリックして頂けると励みになります。


[32 | カートボタン] << [ホーム] >> [34 | Stripeモデルの実装]