[20 | Permission] << [ホーム] >> [22 | カテゴリー登録]
作業は「qrmenu_react」側に移ります。
react-iconsを使用できるようターミナルでインストールします。
コマンド
npm i react-icons@4.2.0 -s
「src/apis.js」ファイルに記述を追加します。
記述追加 【QRMenu/qrmenu_react/src/apis.js】83行目
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 }); }
「qrmenu_react/src/pages」フォルダに「Place.js」ファイルを新規作成します。
新規作成した「src/pages/Place.js」ファイルを以下のように編集します。
新規作成 【Desktop/QRMenu/qrmenu_react/src/pages/Place.js】
import { IoMdArrowBack } from 'react-icons/io'; import { Row, Col, Button } from 'react-bootstrap'; import { useParams, useHistory } from 'react-router-dom'; import React, { useEffect, useState, useContext } from 'react'; import { fetchPlace } from '../apis'; import AuthContext from '../contexts/AuthContext'; import MainLayout from '../layouts/MainLayout'; const Place = () => { const [place, setPlace] = useState({}); 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); } }; useEffect(() => { onFetchPlace(); }, []); return ( <mainLayout> <Row> <Col lg={12}> <div className="mb-4"> <div className="d-flex align-items-center"> <Button variant="link" onClick={onBack}> <IoMdArrowBack size={25} color="black" /> </Button> <h3 className="mb-0 ml-2 mr-2">{place.name}</h3> </div> </div> </Col> </Row> </mainLayout> ) }; export default Place;
「src/router/App.js」ファイルを編集します。
記述編集 【QRMenu/qrmenu_react/src/router/App.js】
import { BrowserRouter, Switch, Route } from 'react-router-dom'; import { ToastContainer } from 'react-toastify'; import React from 'react'; import { AuthProvider } from '../contexts/AuthContext'; import PrivateRoute from './PrivateRoute'; import Home from '../pages/Home'; import Login from '../pages/Login'; import Register from '../pages/Register'; import Places from '../pages/Places'; import Place from '../pages/Place'; function App() { return ( <AuthProvider> <BrowserRouter> <Switch> <Route exact path='/'> <Home /> </Route> <Route exact path='/login'> <Login /> </Route> <Route exact path='/register'> <Register /> </Route> <PrivateRoute exact path='/places/:id'> <Place /> </PrivateRoute> <PrivateRoute exact path='/places'> <Places /> </PrivateRoute> </Switch> </BrowserRouter> <ToastContainer /> </AuthProvider> ) } export default App;
「src/pages/Places.js」ファイルを編集します。
記述編集 【QRMenu/qrmenu_react/src/pages/Places.js】
import { Row, Col, Modal } from 'react-bootstrap'; import { useHistory } from 'react-router-dom'; import { React, useEffect, useState, useContext } from 'react'; import styled from 'styled-components'; import { fetchPlaces } from '../apis'; import AuthContext from '../contexts/AuthContext'; import MainLayout from '../layouts/MainLayout'; import PlaceForm from '../containers/PlaceForm'; const Place = styled.div` margin-bottom: 20px; cursor: pointer; transition: all 0.2s; :hover { transform: scale(1.05); } > div { background-size: cover; height: 200px; border-radius: 5px; } > p { margin-top: 5px; font-size: 20px; font-weight: bold; } `; const AddPlaceButton = styled.div` border: 1px dashed gray; height: 200px; border-radius: 5px; display: flex; aligh-items: center; justify-content: center; padding-top: 5rem; font-size: 20px; cursor: pointer; background-color: white; :hover { background-color: #fbfbfb; } `; const Places = () => { const [places, setPlaces] = useState([]); const [show, setShow] = useState(false); const auth = useContext(AuthContext); const history = useHistory(); const onHide = () => setShow(false); const onShow = () => setShow(true); const onFetchPlaces = async () => { const json = await fetchPlaces(auth.token); if (json) { setPlaces(json); } }; const onDone = () => { onFetchPlaces(); onHide(); } useEffect(() => { onFetchPlaces(); }, []); return ( <MainLayout> <h3>登録済み飲食店</h3> <br/> <Modal show={show} onHide={onHide} centerd> <Modal.Body> <PlaceForm onDone={onDone} /> </Modal.Body> </Modal> <Row> { places.map((place) => ( <Col key={place.id} lg={4}> <Place onClick={() => history.push(`/places/${place.id}`)}> <div style={{ backgroundImage: `url(${place.image})` }}></div> <p>{place.name}</p> </Place> </Col> ))} <Col lg={4}> <AddPlaceButton onClick={onShow}>飲食店登録</AddPlaceButton> </Col> </Row> </MainLayout> ) } export default Places;
これで、登録した飲食店をクリックすると詳細ページにジャンプするようになりました。
↓↓クリックして頂けると励みになります。
[20 | Permission] << [ホーム] >> [22 | カテゴリー登録]