[27 | メニューアイテム削除] << [ホーム] >> [29 | QRコードプリント]
「qrcode.react」をインストールします。
コマンド
npm i qrcode.react@1.0.1 -s
「qrmenu_react/src/components」フォルダに「QRCodeModal.js」ファイルを新規作成します。
新規作成 【QRMenu/qrmenu_react/src/components/QRCodeModal.js】
import React from 'react'; import { Modal, Container, Row, Col } from 'react-bootstrap'; import QRCodeReact from 'qrcode.react'; const QRCodeModal = ({ show, onHide, place }) => ( <Modal show={show} onHide={onHide} size="lg" centered> <Modal.Body className="text-center pt-4"> <Container> <h3>客席 QRコード</h3> <div className="mt-4 mb-4"> <h5 className="mb-0 mr-2"> 全席数: <b>{place.number_of_tables}</b> </h5> </div> <Row> {Array.from({ length: place.number_of_tables }, (_, i) => i + 1).map( (table) => ( <Col key={table} lg={4} md={6} className="mb-4"> <QRCodeReact value={`${window.location.origin}/menu/${place.id}/${table}`} size={200} /> </Col> ) )} </Row> </Container> </Modal.Body> </Modal> ) export default QRCodeModal;
「src/pages/Place.js」ファイルを編集します。
記述編集 【/Users/heyjude/Desktop/QRMenu/qrmenu_react/src/pages/Place.js】
import { IoMdArrowBack } from 'react-icons/io'; import { AiOutlineDelete, AiOutlineQrcode, AioutlineQrcode } from 'react-icons/ai'; import { Row, Col, Button, Modal } from 'react-bootstrap'; import { useParams, useHistory } from 'react-router-dom'; import React, { useEffect, useState, useContext } from 'react'; import styled from 'styled-components'; import { fetchPlace, removePlace, removeCategory, removeMenuItem } from '../apis'; import AuthContext from '../contexts/AuthContext'; import MainLayout from '../layouts/MainLayout'; import MenuItemForm from '../containers/MenuItemForm'; import MenuItem from '../components/MenuItem'; import QRCodeModal from '../components/QRCodeModal'; const Panel = styled.div` background-color: white; padding: 20px; border-radius: 5px; box-shadow: 1px 1px 10px rgba(0,0,0,0.05); `; const Place = () => { const [place, setPlace] = useState({}); const [menuItemFormShow, setMenuItemFormShow] = useState(false); const [selectedItem, setSelectedItem] = useState(null); const [qrCode, setQrCode] = useState(false); const showModal = () => setMenuItemFormShow(true); const hideModal = () => setMenuItemFormShow(false); const showQRModal = () => setQrCode(true); const hideQRModal = () => setQrCode(false); const auth = useContext(AuthContext); const params = useParams(); const history = useHistory(); const onBack = () => history.push("/places"); const onFetchPlace = async () => { const json = await fetchPlace(params.id, auth.token); if(json) { setPlace(json); } }; const onRemovePlace = () => { const c = window.confirm("本当に削除してもよろしいですか?") if (c) { removePlace(params.id, auth.token).then(onBack); } }; const onRemoveCategory = (id) => { const c = window.confirm("本当に削除してもよろしいですか?") if (c) { removeCategory(id, auth.token).then(onFetchPlace); } }; const onRemoveMenuItem = (id) => { const c = window.confirm("本当に削除してもよろしいですか?") if (c) { removeMenuItem(id, auth.token).then(onFetchPlace); } }; useEffect(() => { onFetchPlace(); }, []); return ( <MainLayout> <Row> <Col lg={12}> <div className="mb-4"> <div className="d-flex justify-content-between align-items-center mb-4"> <Button variant="link" onClick={onBack}> <IoMdArrowBack size={25} color="black" /> </Button> <h3 className="mb-0 ml-2 mr-2">{place.name}</h3> <Button variant="link" onClick={onRemovePlace}> <AiOutlineDelete size={25} color="red" /> </Button> </div> <Button variant="link" onClick={showQRModal}> <AiOutlineQrcode size={25} /> </Button> </div> </Col> <Col md={4}> <Panel> <MenuItemForm place={place} onDone={onFetchPlace} /> </Panel> </Col> <Col md={8}> {place?.categories?.map((category) => ( <div key={category.id} className="mb-5"> <div className="d-flex align-items-center mb4"> <h4 className="mb-0 mr-2"> <b>{category.name}</b> </h4> <Button variant="link" onClick={() => onRemoveCategory(category.id)}> <AiOutlineDelete size={25} color="red" /> </Button> </div> <br/> {category.menu_items.map((item) => ( <MenuItem key={item.id} item={item} onEdit={() => { setSelectedItem(item); showModal() }} onRemove={() => onRemoveMenuItem(item.id)} /> ))} </div> ))} </Col> </Row> <Modal show={menuItemFormShow} onHide={hideModal} centerd> <Modal.Body> <h4 className="text-center">メニューアイテム</h4> <MenuItemForm place={place} onDone={() =>{ onFetchPlace(); hideModal() }} item={selectedItem} /> </Modal.Body> </Modal> <QRCodeModal show={qrCode} onHide={hideQRModal} place={place} centered /> </MainLayout> ) }; export default Place;
QRコードボタンを押すと、テーブル席のQRコードが出るようになりました。
管理画面でテーブルの数を増やしてみます。
テーブル席数のQRコードが表示されます。
客席数を変更できるよう実装します。
「src/apis.js」ファイルに記述を追加します。
記述追加 【QRMenu/qrmenu_react/src/apis.js】111行目
import { toast } from 'react-toastify'; function request(path, {data = null, token = null, method = "GET" }) { return fetch(path, { method, headers: { Authorization: token ? `Token ${token}` : "", "Content-Type": "application/json", }, body: method !=="GET" && method !== "DELETE" ? JSON.stringify(data): null, }) .then((response) => { //もし成功したら if (response.ok) { if(method === "DELETE") { return true; } //toast.success("ログイン成功"); return response.json(); } //失敗 return response.json().then((json) => { //JSONエラー if (response.status === 400) { //toast.error("氏名もしくはパスワードに間違いがあります。"); const errors = Object.keys(json).map( (k) => `${(json[k].join(" "))}` ); throw new Error(errors.join(" ")); } throw new Error(JSON.stringify(json)); }) .catch((e) => { if (e.name === "SyntaxError") { throw new Error(response.statusText); } throw new Error(e); }) }) .catch((e) => { //全エラー toast(e.message, { type: "error" }); }) } export function signIn(username, password) { return request("/auth/token/login/", { data: {username, password}, method: "POST", }) } export function register(username, password) { return request("/auth/users/", { data: {username, password}, method: "POST", }) } export function fetchPlaces(token) { return request("/api/places/", {token}); } export function addPlace(data, token) { return request("/api/places/", {data, token, method: "POST" }); } export function uploadImage(image) { const formData = new FormData(); formData.append("file", image); formData.append("upload_preset", "qrmenu_photos"); return fetch("https://api.cloudinary.com/v1_1/dov57gocw/image/upload", { method: "POST", body: formData, }).then((response) => { return response.json(); }); } export function fetchPlace(id, token) { return request(`/api/places/${id}`, { token }); } export function addCategory(data, token) { return request("/api/categories/", {data, token, method: "POST"}); } export function addMenuItems(data, token) { return request("/api/menu_items/", {data, token, method: "POST"}); } export function updateMenuItem(id, data, token) { return request(`/api/menu_items/${id}`, { data, token, method: "PATCH"}); } export function removePlace(id, token) { return request(`/api/places/${id}`, {token, method: "DELETE"}); } export function removeCategory(id, token) { return request(`/api/categories/${id}`, {token, method: "DELETE"}); } export function removeMenuItem(id, token) { return request(`/api/menu_items/${id}`, {token, method: "DELETE"}); } export function updatePlace(id, data, token) { return request(`/api/places/${id}`, { data, token, method: "PATCH"}) }
「src/pages/Place.js」ファイルを編集します。
記述編集 【QRMenu/qrmenu_react/src/pages/Place.js】
import { IoMdArrowBack } from 'react-icons/io'; import { AiOutlineDelete, AiOutlineQrcode, AioutlineQrcode } from 'react-icons/ai'; import { Row, Col, Button, Modal } from 'react-bootstrap'; import { useParams, useHistory } from 'react-router-dom'; import React, { useEffect, useState, useContext } from 'react'; import styled from 'styled-components'; import { fetchPlace, removePlace, removeCategory, removeMenuItem, updatePlace } from '../apis'; import AuthContext from '../contexts/AuthContext'; import MainLayout from '../layouts/MainLayout'; import MenuItemForm from '../containers/MenuItemForm'; import MenuItem from '../components/MenuItem'; import QRCodeModal from '../components/QRCodeModal'; const Panel = styled.div` background-color: white; padding: 20px; border-radius: 5px; box-shadow: 1px 1px 10px rgba(0,0,0,0.05); `; const Place = () => { const [place, setPlace] = useState({}); const [menuItemFormShow, setMenuItemFormShow] = useState(false); const [selectedItem, setSelectedItem] = useState(null); const [qrCode, setQrCode] = useState(false); const showModal = () => setMenuItemFormShow(true); const hideModal = () => setMenuItemFormShow(false); const showQRModal = () => setQrCode(true); const hideQRModal = () => setQrCode(false); const auth = useContext(AuthContext); const params = useParams(); const history = useHistory(); const onBack = () => history.push("/places"); const onFetchPlace = async () => { const json = await fetchPlace(params.id, auth.token); if(json) { setPlace(json); } }; const onRemovePlace = () => { const c = window.confirm("本当に削除してもよろしいですか?") if (c) { removePlace(params.id, auth.token).then(onBack); } }; const onRemoveCategory = (id) => { const c = window.confirm("本当に削除してもよろしいですか?") if (c) { removeCategory(id, auth.token).then(onFetchPlace); } }; const onRemoveMenuItem = (id) => { const c = window.confirm("本当に削除してもよろしいですか?") if (c) { removeMenuItem(id, auth.token).then(onFetchPlace); } }; const onUpdatePlace = (tables) => { updatePlace(place.id, {number_of_tables: tables }, auth.token).then( (json) => { if (json) { setPlace(json); } } ) } useEffect(() => { onFetchPlace(); }, []); return ( <MainLayout> <Row> <Col lg={12}> <div className="mb-4"> <div className="d-flex justify-content-between align-items-center mb-4"> <Button variant="link" onClick={onBack}> <IoMdArrowBack size={25} color="black" /> </Button> <h3 className="mb-0 ml-2 mr-2">{place.name}</h3> <Button variant="link" onClick={onRemovePlace}> <AiOutlineDelete size={25} color="red" /> </Button> </div> <Button variant="link" onClick={showQRModal}> <AiOutlineQrcode size={25} /> </Button> </div> </Col> <Col md={4}> <Panel> <MenuItemForm place={place} onDone={onFetchPlace} /> </Panel> </Col> <Col md={8}> {place?.categories?.map((category) => ( <div key={category.id} className="mb-5"> <div className="d-flex align-items-center mb4"> <h4 className="mb-0 mr-2"> <b>{category.name}</b> </h4> <Button variant="link" onClick={() => onRemoveCategory(category.id)}> <AiOutlineDelete size={25} color="red" /> </Button> </div> <br/> {category.menu_items.map((item) => ( <MenuItem key={item.id} item={item} onEdit={() => { setSelectedItem(item); showModal() }} onRemove={() => onRemoveMenuItem(item.id)} /> ))} </div> ))} </Col> </Row> <Modal show={menuItemFormShow} onHide={hideModal} centerd> <Modal.Body> <h4 className="text-center">メニューアイテム</h4> <MenuItemForm place={place} onDone={() =>{ onFetchPlace(); hideModal() }} item={selectedItem} /> </Modal.Body> </Modal> <QRCodeModal show={qrCode} onHide={hideQRModal} place={place} centered onUpdatePlace={onUpdatePlace} /> </MainLayout> ) }; export default Place;
「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 QRCodeReact from 'qrcode.react'; import styled from 'styled-components'; const OperationButton = styled(Button)` width: 30px; height: 30px; margin: 0 10px; font-size: 20px; line-height: 18px; `; 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"> <QRCodeReact value={`${window.location.origin}/menu/${place.id}/${table}`} size={200} /> </Col> ) )} </Row> </Container> </Modal.Body> </Modal> ) export default QRCodeModal;
+ボタンとーボタンで客席数を変えることができるようになりました。
↓↓クリックして頂けると励みになります。
[27 | メニューアイテム削除] << [ホーム] >> [29 | QRコードプリント]