테이프 요금 계산으로 시장 응용 프로그램 구축

123494 단어

소개하다.


전염병 사태로 집안에 갇히면서 시장 앱이 사람들이 제품을 구매하는 주요 장소가 되면서 대중들의 관심이 급격히 높아졌다.시장 모델은 왜 온라인 시장이 이렇게 인기가 많고 유익한지 설명한다.그것은 모든 시장과 리키 시장을 건설할 수 있으며, 초기 재고가 필요 없고, 배로 성장할 수 있으며, 모든 사람에게 이롭다. 판매자, 구매자, 물론 시장 소유자도 있다.
인터넷에서 제품을 판매하고 대량의 마케팅 업무를 하지 않는 것은 판매자에게 매우 매력적이다.Marketplace 응용 프로그램은 자신의 전자상거래 사이트/응용 프로그램을 만든 다음에 데이터를 더 간단하고 빨리 얻으려고 노력한다.
광범위한 선택과 가격, 그리고 제품을 비교하는 능력이 있기 때문에 고객이 제품을 구매하는 것도 편리하다.
시장을 가지고 있으면 당신에게 많은 효과적인 수익 창출 방식을 제공할 수 있다.광고, 매 거래는 일정 비율의 비용을 받고 more.도 많기 때문에 우리는 깊이 있게 이해하고 어떻게 스스로 하나를 만드는지 알아봅시다!

시작해보도록 하겠습니다.

  • 설정 React
  • 먼저 creact-react-app를 사용하여 템플릿을 작성합니다.
    npx create-react-app marketplace
    
  • 설치 재료 인터페이스
  • Material UI를 사용하여 CSS를 최종적으로 작성하지 않도록 프런트엔드를 설계합니다.
    cd marketplace
    npm install @mui/material @emotion/react @emotion/styled
    
  • 제품 구성 요소 생성
  • src에 디렉터리를 만들고 components라고 명명하면 우리가 구축하고자 하는 모든 다른 구성 요소를 놓을 것입니다!
    다른 디렉토리를 만들고 이름을 Product로 지정합니다.Product.js 디렉터리에 Product를 만듭니다.이 구성 요소는 우리가 가지고 있는 제품 목록을 보여 줍니다.우선, 우리는 정적 제품 목록을 순환적으로 훑어볼 것이다
    import React from "react";
    import {
      Box,
      Card,
      CardActions,
      CardContent,
      Button,
      Typography,
      Rating,
    } from "@mui/material";
    
    const Products = [
      {
        title: "Oculus Quest All-in-one VR Gaming Headset",
        price: "11.96",
        rating: 5,
      },
      {
        title: "Nintendo Switch with Neon Blue and Neon Red Joy‑Con",
        price: "15.96",
        rating: 3,
      },
      {
        title: "Mass Effect",
        price: "23",
        rating: 5,
      },
      {
        title: "The LeanStartup2: How constant innovative creators",
        price: "9.96",
        rating: 2,
      },
      {
        title: "Dual Shock Controller",
        price: "19.96",
        rating: 5,
      },
    ];
    
    function Product() {
      return (
        <Box
          sx={{
            display: "flex",
            flexDirection: "row",
            justifyContent: "space-between",
            alignItems: "start",
          }}
        >
          {Products.map((product) => (
            <Card
              sx={{
                maxHeight: 450,
                minWidth: 100,
                width: "25%",
                margin: "1.5rem",
                display: "flex",
                flexDirection: "column",
                justifyContent: "space-between",
                alignItems: "start",
              }}
            >
              <CardContent>
                <Typography gutterBottom variant="h5" component="div">
                  {product.title}
                </Typography>
                <Typography gutterBottom variant="h5" component="div">
                  ${product.price}
                </Typography>
                <Rating name="read-only" value={product.rating} readOnly />
              </CardContent>
              <CardActions>
                <Button variant="contained" size="small">
                  Buy now
                </Button>
              </CardActions>
            </Card>
          ))}
        </Box>
      );
    }
    
    export default Product;
    
  • 헤더 어셈블리를 생성합니다.
  • components 내부에 디렉터리를 만들고 헤더로 이름을 붙입니다. 그 안에 파일을 만들고 Header.js 라고 이름을 붙입니다.이 파일은 제목을 포함하고 프로그램의 이름을 표시한 다음 사용자 로그인/로그아웃 단추를 표시합니다.
    import React from "react";
    
    import Product from "./components/product/Product";
    import Header from "./components/header/Header";
    
    function App() {
      return (
        <>
          <Header />
          <Product />
        </>
      );
    }
    
    export default App;
    
    이렇게 해야 합니다.
  • API를 준비할 때가 됐어요!
  • Marketplace 애플리케이션의 API를 쉽게 액세스할 수 있습니다.네가 해야 할 일은 Canonic에서 이 제품을 복제하는 것이다. project 너는 완성했다.코드를 작성하지 않고도 통합에 필요한 백엔드, API 및 문서를 제공합니다.0auth 제공 프로그램에 자신의 리셋 URI, 클라이언트 ID 및 비밀번호를 추가하기만 하면 됩니다.

    클론 항목은 CMS 항목을 복제하지 않으므로 Products에 CMS 항목을 추가해야 합니다.

    GraphQL과의 백엔드 통합


    이제 통합합시다!이제 API가 준비되었으므로 GraphQL 패키지를 계속 설치해 보겠습니다.
  • GraphQL 패키지 설치
  • 백엔드에서 데이터를 추출하려면 Apollo Client 및 GraphQL 두 개의 패키지가 필요합니다.
    npm i @apollo/client graphql
    
  • 구성 GraphQL 및 백엔드 커뮤니케이션
  • 프로젝트 디렉터리에 Apollo 클라이언트를 설정하고 index.js에 Apollo 클라이언트를 설정하여 백엔드와 통신하도록 합니다.

    Note to replace the uri with the one you'll get from Canonic.


            import React from "react";
            import ReactDOM from "react-dom";
            import { ApolloClient, InMemoryCache, ApolloProvider } from "@apollo/client";
    
            import App from "./App";
    
            const client = new ApolloClient({
              uri: "https://marketplace-app.can.canonic.dev/graphql", //You can replace this with your URI
              cache: new InMemoryCache(),
            });
    
            ReactDOM.render(
              <React.StrictMode>
                <ApolloProvider client={client}>
                  <App />
                </ApolloProvider>
              </React.StrictMode>,
              document.getElementById("root")
            );
    
  • 조회 데이터
  • 데이터를 조회하기 위해서, 우리는 src에 gql라는 디렉터리를 만들고, 그 중에서 query.js라는 파일을 만들 것입니다.그것은 백엔드에서 우리가 필요로 하는 모든 데이터를 쓸 것이다.
            import { gql } from "@apollo/client";
    
            export const LOGIN_WITH_GOOGLE = gql`
              query {
                getLoginUrlsForLogin {
                  GOOGLE
                }
              }
            `;
    
            export const GET_PRODUCTS = gql`
              query {
                products {
                  title
                  _id
                  price
                  ratings
                  priceApiId
                  image {
                    url
                    name
                  }
                }
              }
            `;
    
  • Google 0auth를 사용하여 로그인 설정
  • Header 구성 요소로 돌아가서 이전 단계에서 설명한 검색어를 가져오고 Apollo가 datahook에서 얻은 useQuery 변수에 저장합니다
            import { useQuery } from "@apollo/client";
            import { LOGIN_WITH_GOOGLE } from "../../gql/query";
    
                const { data, loading: loginDataLoading } = useQuery(LOGIN_WITH_GOOGLE)
    
    다음 JSX를 추가하여 로그인 버튼을 표시합니다.data?.getLoginUrlsForLogin?.GOOGLE 여기서 GOOGLE 대상은 로그인과 리셋 링크를 포함하고 사용자는 자신에 로그인할 수 있다.
            <Box sx={{ flexGrow: 0 }}>
              <Tooltip title="Account">
                 {loginDataLoading && <CircularProgress color="secondary" />}
                    <a href={data?.getLoginUrlsForLogin?.GOOGLE}>
                        <Button variant="contained" startIcon={<GoogleIcon />}>
                           <span sx={{ textDecoration: "none" }}>Login</span>
                        </Button>
                    </a>
            </Box>
    
    이러한 요소를 추가하면 Header 구성 요소가 다음과 같이 표시됩니다.
            import React from "react";
            import { useQuery } from "@apollo/client";
            import {
              AppBar,
              Box,
              Toolbar,
              Typography,
              Container,
              Button,
              Tooltip,
              CircularProgress,
            } from "@mui/material";
            import GoogleIcon from "@mui/icons-material/Google";
    
            import { LOGIN_WITH_GOOGLE } from "../../gql/query";
    
            function Header() {
              const { data, loading: loginDataLoading } = useQuery(LOGIN_WITH_GOOGLE); 
              return (
                <AppBar position="static">
                  <Container maxWidth="xl">
                    <Toolbar disableGutters sx={{ justifyContent: "space-between" }}>
                      <Typography
                        variant="h6"
                        noWrap
                        component="div"
                        sx={{ mr: 2, display: { xs: "none", md: "flex" } }}
                      >
                        Marketplace
                      </Typography>
                      <Box sx={{ flexGrow: 0 }}>
                        <Tooltip title="Account">
                          {loginDataLoading && <CircularProgress color="secondary" />}
                          <a href={data?.getLoginUrlsForLogin?.GOOGLE}>
                            <Button variant="contained" startIcon={<GoogleIcon />}>
                              <span sx={{ textDecoration: "none" }}>Login</span>
                            </Button>
                          </a>
                        </Tooltip>
                      </Box>
                    </Toolbar>
                  </Container>
                </AppBar>
              );
            }
    
            export default Header;
    
  • 로그인 사용자 상태입니다.
  • 아직 Header 구성 요소가 완성되지 않았습니다. 사용자가 프로그램에 로그인할 수 있는 기능이 추가되었습니다. 사용자의 정보를 검색하고 저장해야 합니다. 그러면 로그인 여부를 확인할 수 있고, 회의를 지속할 수 있으며, 이름, 성, 이메일 ID, 그리고 모든 좋은 것들을 얻을 수 있습니다.우리가 그것을 위해 준비를 하자. 우선 우리는 돌변을 창조해야 한다.mutation.js 디렉터리에 gql라는 파일을 만듭니다.
            import { gql } from "@apollo/client";
    
            export const LOGIN_WITH_GOOGLE_MUTATION = gql`
              mutation Login($code: String!, $service: String!) {
                loginForLogin(code: $code, service: $service) {
                  token
                  user {
                    email
                    firstName
                    lastName
                    avatar {
                      url
                    }
                  }
                }
              }
            `;
    
    현재 우리의 돌연변이가 준비되어 있습니다. Header 구성 요소에서 그것을 호출해서 그것을 되돌릴 수 있습니다.돌변은 다음과 같습니다.
            import { useMutation } from "@apollo/client";
    
            const [loginMutation, { data: mutationData }] = useMutation(LOGIN_WITH_GOOGLE_MUTATION);
            const urlCode = new URLSearchParams(window.location.search).get("code"); //We receive a code after a successful sign in, here pulling that code from the URL
                if (urlCode) {
                  loginMutation({ variables: { code: urlCode, service: "GOOGLE" } });
                    }
    
    사용자가 성공적으로 로그인하면 it, 구글, 페이스북, GitHub 공급자로부터 코드를 받을 수 있습니다.우리는 윈도우즈 대상URLSearchParams(window.location.search).get("code")에 대한 호출을 사용하여 코드를 얻을 수 있으며, 코드를 저장하면 변이에 변수로 전달할 수 있다.서비스에서 당신이 사용하고 있는 서비스를 적어야 합니다. 이 앱은 구글만 사용하기 때문에 Google은 정태적으로 구글을 추가했습니다.
    우리는 이 변이를 의존항으로 빈 그룹을 가진useEffect 갈고리에 전달할 것입니다.우리는 변이에서 얻은 데이터를 다른 곳에서 사용할 수 있도록 상태를 저장해야 한다. 그리고 변이에서 받은 영패를 로컬 저장소에 저장해서 사용자 로그인 세션을 지속시킬 수 있다.
            const [accessToken, setAccessToken] = useState();
            const [isLoggedIn,setIsLoggedIn] = useState()
    
            useEffect(() => {
                const urlCode = new URLSearchParams(window.location.search).get("code");
                if (urlCode) {
                  loginMutation({ variables: { code: urlCode, service: "GOOGLE" } }); 
              }, []);
    
            useEffect(() => {
                setAccessToken(mutationData?.loginForLogin?.token);
                setIsLoggedIn(mutationData?.loginForLogin?.user);
                if (accessToken) localStorage.setItem("_id", accessToken);
              }, [accessToken, mutationData, setIsLoggedIn]);
    
    
    그러나 다른 곳에서도 이 상태isLoggedIn가 필요하기 때문에 응용 프로그램으로 이동하는 것이 더 좋다.이것은 모든 구성 요소의 부모 구성 요소이기 때문에, 헤더 구성 요소를 도구로 받아들일 것입니다.그래서 이 앱은js는 다음과 같습니다.
            import React, { useState } from "react";
    
            import Header from "./components/header/Header";
            import Product from "./components/product/Product";
    
            function App() {
              const [isLoggedIn, setIsLoggedIn] = useState(); 
    
              return (
                <>
                  {
                    <div className="App">
                      <Header setIsLoggedIn={setIsLoggedIn} isLoggedIn={isLoggedIn} />
                      <Product />
                    </div>
                  }
                </>
              );
            }
    
            export default App;
    
    사용자가 로그아웃할 수 있도록 방법도 추가할 것입니다.이를 위해 Material UI의 구성 요소를 사용하고 모든 UI 개선 사항을 추가하면 제목 구성 요소는 다음과 같습니다
            import React, { useEffect, useState, useCallback } from "react";
            import { useQuery, useMutation } from "@apollo/client";
            import {
              AppBar,
              Box,
              Toolbar,
              IconButton,
              Typography,
              Menu,
              Container,
              Avatar,
              Button,
              Tooltip,
              MenuItem,
              CircularProgress,
            } from "@mui/material";
            import GoogleIcon from "@mui/icons-material/Google";
    
            import { LOGIN_WITH_GOOGLE } from "../../gql/query";
            import { LOGIN_WITH_GOOGLE_MUTATION } from "../../gql/mutation";
    
            function Header({ setIsLoggedIn, isLoggedIn }) {
              const [accessToken, setAccessToken] = useState();
              const { data, loading: loginDataLoading } = useQuery(LOGIN_WITH_GOOGLE);
              const [loginMutation, { data: mutationData }] = useMutation(
                LOGIN_WITH_GOOGLE_MUTATION
              );
              useEffect(() => {
                const urlCode = new URLSearchParams(window.location.search).get("code"); 
                if (urlCode) {
                  loginMutation({ variables: { code: urlCode, service: "GOOGLE" } }); 
                }
              }, []);
              useEffect(() => {
                setAccessToken(mutationData?.loginForLogin?.token);
                setIsLoggedIn(mutationData?.loginForLogin?.user);
                if (accessToken) localStorage.setItem("_id", accessToken); 
              }, [accessToken, mutationData, setIsLoggedIn]);
    
              const [anchorElNav, setAnchorElNav] = React.useState(null);
              const [anchorElUser, setAnchorElUser] = React.useState(null);
    
              const handleOpenUserMenu = useCallback((event) => {
                setAnchorElUser(event.currentTarget);
              });
    
              const handleCloseNavMenu = useCallback(() => {
                setAnchorElNav(null);
              });
    
              const handleCloseUserMenu = useCallback(() => {
                setAnchorElUser(null);
              });
    
              const onLogout = useCallback(() => {
                localStorage.removeItem("_id"); 
              });
    
              return (
                <AppBar position="static">
                  <Container maxWidth="xl">
                    <Toolbar disableGutters sx={{ justifyContent: "space-between" }}>
                      <Typography
                        variant="h6"
                        noWrap
                        component="div"
                        sx={{ mr: 2, display: { xs: "none", md: "flex" } }}
                      >
                        Marketplace
                      </Typography>
    
                      <Box sx={{ flexGrow: 0 }}>
                        <Tooltip title="Account">
                          {loginDataLoading ? (
                            <CircularProgress color="secondary" />
                          ) : !isLoggedIn && !localStorage.getItem("_id") ? ( 
                            <a href={data?.getLoginUrlsForLogin?.GOOGLE}>
                              <Button variant="contained" startIcon={<GoogleIcon />}>
                                <span sx={{ textDecoration: "none" }}>Login</span>
                              </Button>
                            </a>
                          ) : (
                            <IconButton onClick={handleOpenUserMenu} sx={{ p: 0 }}>
                              {isLoggedIn?.avatar?.url ? (
                                <Avatar alt="User" src={isLoggedIn.avatar.url} />
                              ) : (
                                <Avatar src="/broken-image.jpg" />
                              )}
                            </IconButton>
                          )}
                        </Tooltip>
                        <Menu
                          sx={{ mt: "45px" }}
                          id="menu-appbar"
                          anchorEl={anchorElUser}
                          anchorOrigin={{
                            vertical: "top",
                            horizontal: "right",
                          }}
                          keepMounted
                          transformOrigin={{
                            vertical: "top",
                            horizontal: "right",
                          }}
                          open={Boolean(anchorElUser)}
                          onClose={handleCloseUserMenu}
                        >
                          <MenuItem onClick={handleCloseNavMenu}>
                            <Typography textAlign="center">
                              <a
                                onClick={onLogout}
                                href={`https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=${window.origin}`}
                              >
                                Logout
                              </a>
                            </Typography>
                          </MenuItem>
                        </Menu>
                      </Box>
                    </Toolbar>
                  </Container>
                </AppBar>
              );
            }
    
            export default Header;
    
  • 제품 구성 요소 완성
  • 우리는 지금 Product 구성 요소로 중점을 옮길 것이다.구성 요소의 단순성을 유지하고 구성 요소가 복잡하지 않도록 하기 위해서, 부모 구성 요소 Product 로 사용할 주 구성 요소를 만들 것입니다.구성 요소 내에 디렉터리를 만들고 그것을 Home이라고 부르며 Home을 만들어서 설정합니다.안에 js 파일이 있습니다.
            import React, { useMemo } from "react";
            import { useQuery } from "@apollo/client";
            import { Box, CircularProgress } from "@mui/material";
    
            import Product from "../product/Product.js";
            import { GET_PRODUCTS } from "../../gql/query";
    
            function Home() {
              const { data, loading: productsLoading } = useQuery(GET_PRODUCTS); 
              const products = useMemo(() => data?.products || [], [data?.products]); 
    
              return (
                <Box
                  sx={{
                    display: "flex",
                    flexDirection: "row",
                    flexWrap: "wrap",
                    gap: "4rem",
                    marginTop: "4rem",
                  }}
                >
                  {productsLoading && (
                    <CircularProgress sx={{ position: "absolute", left: "50%" }} />
                  )}
                  {products.map((item, i) => {
                    return (
                      <Product
                        key={i}
                        id={item.id}
                        title={item.title}
                        image={item.image.url}
                        price={item.price}
                        rating={item.ratings}
                        price_api={item.priceApiId}
                      />
                    );
                  })}
                </Box>
              );
            }
    
            export default Home;
    
    현재 우리는 동적으로 데이터를 수신하고 있으며, 우리는 마침내 제품에서 정적 데이터 그룹을 던질 수 있다.js, 우리 시작합시다.
            import React from "react";
            import {
              Card,
              CardContent,
              CardMedia,
              Typography,
              Rating,
            } from "@mui/material";
    
            function Product({ title, price, rating, image, price_api }) {
              return (
                <Card
                  sx={{
                    maxHeight: 450,
                    minWidth: 100,
                    width: "25%",
                    margin: "1.5rem",
                    display: "flex",
                    flexDirection: "column",
                    justifyContent: "space-between",
                    alignItems: "start",
                  }}
                >
                  <CardMedia
                    component="img"
                    alt="title"
                    height="auto"
                    image={image}
                    sx={{ objectFit: "contain", maxHeight: "200px" }}
                  />
                  <CardContent>
                    <Typography gutterBottom variant="h5" component="div">
                      {title}
                    </Typography>
                    <Typography gutterBottom variant="h5" component="div">
                      ${price}
                    </Typography>
                    <Rating name="read-only" value={rating} readOnly />
                  </CardContent>
                </Card>
              );
            }
    
            export default Product;
    
    우리는 거의 이곳을 완성했다. 단지 Stripe’s client only checkout이를 위해서는 먼저 Stripe에 계정이 있어야 하고, Stripe의 API 키가 있어야 한다.너는 열쇠를 받을 수 있다here.그리고 stripe를 설치할 거예요.
            npm install --save @stripe/react-stripe-js @stripe/stripe-js
    
    이제 이 모든 것이 끝났습니다. Home 구성 요소로 돌아가겠습니다."Buy now"버튼의 handle click이므로 비동기 함수를 만듭니다.
            import { loadStripe } from "@stripe/stripe-js";
    
            const stripePromise = loadStripe(process.env.REACT_APP_STRIPE_API);
            const handleClick = async () => {
                  setLoading(true);
                  const stripe = await stripePromise;
                  const { error } = await stripe.redirectToCheckout({
                    lineItems: [
                      {
                        price: price_api, 
                        quantity: 1,
                      },
                    ],
                    mode: "payment",
                    cancelUrl: "https://canonic-marketplace.netlify.app/", 
                    successUrl: "https://canonic-marketplace.netlify.app/", 
                  if (error) {
                    setLoading(false);
                    console.log("The error ", error);
                  }
              };
    
    cancelUrl과 successUrl을 사용자 URL으로 바꿀 수 있습니다. process.env.REACT_APP_STRIPE_API 사용자 API 키를 추가하는 것이 아니라.여기서 price api를 가격 키의 값으로 사용합니다.stripe에서 모든 제품은 유일하다product price ID. 저는 모든 제품의 가격 ID를 Canonic CMS에 저장했기 때문에 당신은 그것을 값으로 사용할 수 있습니다.
    프로젝트의 CMS에서 price api 필드에 자신의 제품의 price ID를 추가할 수 있습니다.
    우리가 할 수 있는 마지막 검증은 계속하기 전에 사용자가 로그인했는지 확인하는 것이다. 왜냐하면 우리는 응용 프로그램 구성 요소에 isLoggedIn 있기 때문에, 우리는 그것을 메인 구성 요소에 쉽게 전달할 수 있기 때문이다.
            import React, { useState } from "react";
    
            import Header from "./components/header/Header";
            import Home from "./components/home/Home";
    
            function App() {
              const [isLoggedIn, setIsLoggedIn] = useState(); 
    
              return (
                <>
                  {
                    <div className="App">
                      <Header setIsLoggedIn={setIsLoggedIn} isLoggedIn={isLoggedIn} />
                      **<Home isLoggedIn={isLoggedIn} />**
                    </div>
                  }
                </>
              );
            }
    
            export default App;
    
    handleClick 기능을 불러오는 상태와 함께 전달해야 합니다. 불러오는 상태를 사용하면 사용자가 클릭한 후에 '즉시 구매' 단추를 사용하지 않기 때문에 Stripe를 여러 번 호출하지 않습니다.
            import React, { useState, useEffect, useMemo } from "react";
            import {  useQuery } from "@apollo/client";
            import { loadStripe } from "@stripe/stripe-js";
            import { Box, CircularProgress } from "@mui/material";
    
            import Product from "../product/Product.js";
            import { GET_PRODUCTS } from "../../gql/query";
    
            function Home({ **isLoggedIn** }) {
              const { data, loading: productsLoading } = useQuery(GET_PRODUCTS); 
              const products = useMemo(() => data?.products || [], [data?.products]);
              const stripePromise = loadStripe(process.env.REACT_APP_STRIPE_API); 
              const [loading, setLoading] = useState();
    
              const handleClick = async (price_api, title) => {
    
                if (isLoggedIn) {
                  setLoading(true);
                  const stripe = await stripePromise;
                  const { error } = await stripe.redirectToCheckout({
                    lineItems: [
                      {
                        price: price_api, 
                        quantity: 1,
                      },
                    ],
                    mode: "payment",
                    cancelUrl: window.origin,
                    successUrl: window.origin + `?session_id=${title}`,
                  });
                  if (error) {
                    setLoading(false);
                  }
                } else alert("Please log in to continue");
              };
    
              return (
                <Box
                  sx={{
                    display: "flex",
                    flexDirection: "row",
                    flexWrap: "wrap",
                    gap: "4rem",
                    marginTop: "4rem",
                  }}
                >
                  {productsLoading && (
                    <CircularProgress sx={{ position: "absolute", left: "50%" }} />
                  )}
                  {products.map((item, i) => {
                    return (
                      <Product
                        key={i}
                        id={item.id}
                        title={item.title}
                        image={item.image.url}
                        price={item.price}
                        rating={item.ratings}
                        price_api={item.priceApiId}
                        **handleClick={handleClick}
                        loading={loading}**
                      />
                    );
                  })}
                </Box>
              );
            }
    
            export default Home;
    
    제품 구성 요소는handleClick과loading의 도구를 받고 있습니다. 드디어 Buy now 단추를 만들 수 있습니다.
            import React from "react";
            import {
              Card,
              CardActions,
              CardContent,
              CardMedia,
              Button,
              Typography,
              Rating,
            } from "@mui/material";
    
            function Product({
              title,
              price,
              rating,
              image,
              price_api,
              handleClick,
              loading,
            }) {
              return (
                <Card
                  sx={{
                    maxHeight: 450,
                    minWidth: 100,
                    width: "25%",
                    margin: "1.5rem",
                    display: "flex",
                    flexDirection: "column",
                    justifyContent: "space-between",
                    alignItems: "start",
                  }}
                >
                  <CardMedia
                    component="img"
                    alt={title}
                    height="auto"
                    image={image}
                    sx={{ objectFit: "contain", maxHeight: "200px" }}
                  />
                  <CardContent>
                    <Typography gutterBottom variant="h5" component="div">
                      {title}
                    </Typography>
                    <Typography gutterBottom variant="h5" component="div">
                      ${price}
                    </Typography>
                    <Rating name="read-only" value={rating} readOnly />
                  </CardContent>
                  <CardActions>
                    <Button
                      variant="contained"
                      size="small"
                      onClick={() => handleClick(price_api, title)} 
                      disabled={loading}
                    >
                      Buy now
                    </Button>
                  </CardActions>
                </Card>
              );
            }
    
            export default Product;
    
    이것만 있으면 우리는 우리의 앞부분을 끝낼 수 있다.

    상금! - 상금!이메일 및 알림 보내기


    우리는 제품을 구매할 때 느슨한 알림을 보내거나 이메일 알림을 보내는 등 몇 가지 작업을 수행하기 위해 웹훅을 추가할 수 있다.어떻게 하는지 보여줘.
  • Webhook
  • 구성
    Canonic에서 클론 항목을 열고 API로 이동하여 Notify table을 선택합니다.createNotify endpoint를 누르면 슬랙의 메시지 웹훅을 볼 수 있습니다. 이를 누르면 자신의 트리거 URL과 메시지체로 트리거 URL과 메시지체를 바꿀 수 있습니다.이 점에 연결하면 Canonic의 전자메일 웹훅을 발견할 수 있습니다. 거기에서도 전자메일 테마와 본문을 내용으로 바꿀 수 있습니다.
  • 프런트엔드 구성
  • 이 네트워크 갈고리들을 촉발하기 위해서 우리는 변이를 진행해야 한다.우리 먼저 우리의 유전자 돌연변이를 선포합시다.js 파일
                export const NOTIFY = gql`
                  mutation Notify($title: String!) {
                    createNotify(input: { title: $title }) {
                      title
                    }
                  }
                `;
    
    최종 파일은 다음과 같습니다.
                import { gql } from "@apollo/client";
    
                export const LOGIN_WITH_GOOGLE_MUTATION = gql`
                  mutation Login($code: String!, $service: String!) {
                    #This mutation is used to get logged in user's details
                    loginForLogin(code: $code, service: $service) {
                      #We feed in code which we get after user successfully signs in, services are the 0auth services we are using such as Google,Github and Facebook.
                      token
                      user {
                        email
                        firstName
                        lastName
                        avatar {
                          url
                        }
                      }
                    }
                  }
                `;
    
                export const NOTIFY = gql`
                  mutation Notify($title: String!) {
                    createNotify(input: { title: $title }) {
                      title
                    }
                  }
                `;
    
    우리는 반드시 집에서 이런 돌변을 촉발해야 한다.Home 구성 요소로 돌아가서handleClick 함수 successUrl 를 수정해서 제품이 성공적으로 서명되었을 때 URL에 제품의 제목을 포함할 수 있도록 합니다.
                const handleClick = async (price_api, title) => {
    
                    if (isLoggedIn) {
                      setLoading(true);
                      const stripe = await stripePromise;
                      const { error } = await stripe.redirectToCheckout({
                        lineItems: [
                          {
                          price: price_api, 
                            quantity: 1,
                          },
                        ],
                        mode: "payment",
                        cancelUrl: window.origin,
                        successUrl: window.origin + `?session_id=${title}`,
                      });
                      if (error) {
                        setLoading(false);
                      }
                    } else alert("Please log in to continue");
                  };
    
    또한 URL에 제품 제목이 포함되어 있는지 확인하기 위해useEffect를 빈 의존 항목 그룹에 추가합니다
                useEffect(() => {
                    const hasSuccessUrl = new URLSearchParams(window.location.search).get(
                      "session_id"
                    ); 
                    if (hasSuccessUrl) {
                     //Do something
                    }
                  }, []);
    
    이제 모든 것이 준비되었으니 우리는 돌변을 일으킬 수 있다
                import { useMutation } from "@apollo/client";
                import { NOTIFY } from "../../gql/mutation";
    
                const [notify] = useMutation(NOTIFY);
    
                useEffect(() => {
                    const hasSuccessUrl = new URLSearchParams(window.location.search).get(
                      "session_id"
                    ); 
                    if (hasSuccessUrl) {
                      notify({ variables: { title: hasSuccessUrl } });
                    }
                  }, []);
    
    마지막 파일은 이렇습니다.
    
    import React, { useState, useEffect, useMemo } from "react";
    import { useMutation, useQuery } from "@apollo/client";
    import { NOTIFY } from "../../gql/mutation";
    import { loadStripe } from "@stripe/stripe-js";
    import { Box, CircularProgress } from "@mui/material";
    
    import Product from "../product/Product.js";
    import { GET_PRODUCTS } from "../../gql/query";
    
    function Home({ isLoggedIn }) {
      const { data, loading: productsLoading } = 
      useQuery(GET_PRODUCTS); 
      const products = useMemo(() => data?.products || [], [data?.products]); 
      const stripePromise = loadStripe(process.env.REACT_APP_STRIPE_API); 
      const [loading, setLoading] = useState(); 
      const [notify] = useMutation(NOTIFY);
    
      const handleClick = async (price_api, title) => {
                    if (isLoggedIn) {
                      setLoading(true);
                      const stripe = await stripePromise;
                      const { error } = await stripe.redirectToCheckout({
                        lineItems: [
                          {
                            price: price_api, 
                            quantity: 1,
                          },
                        ],
                        mode: "payment",
                        cancelUrl: window.origin,
                        successUrl: window.origin + `?session_id=${title}`, 
                      });
    
                      if (error) {
                        setLoading(false);
                      }
                    } else alert("Please log in to continue");
                  };
    
                  useEffect(() => {
                    const hasSuccessUrl = new URLSearchParams(window.location.search).get(
                      "session_id"
                    ); 
                    if (hasSuccessUrl) {
                      notify({ variables: { title: hasSuccessUrl } });
                    }
                  }, []);
                  return (
                    <Box
                      sx={{
                        display: "flex",
                        flexDirection: "row",
                        flexWrap: "wrap",
                        gap: "4rem",
                        marginTop: "4rem",
                      }}
                    >
                      {productsLoading && (
                        <CircularProgress sx={{ position: "absolute", left: "50%" }} />
                      )}
                      {products.map((item, i) => {
                        return (
                          <Product
                            key={i}
                            id={item.id}
                            title={item.title}
                            image={item.image.url}
                            price={item.price}
                            rating={item.ratings}
                            price_api={item.priceApiId}
                            handleClick={handleClick}
                            loading={loading}
                          />
                        );
                      })}
                    </Box>
                  );
                }
    
      export default Home;
    
    
    일단 네가 여기에 도착하면, 너는 시장 프로젝트를 성공적으로 완성할 수 있을 것이다.
    이 예제 항목을 복제할 수 있습니다.우리는 이 안내서가 당신이 자신의 시장 응용 프로그램을 만드는 데 도움을 줄 수 있기를 바랍니다.만약 당신이 원한다면, 우리 불협화음의 지역사회에서 우리와 나누세요.만약 당신이 아직 회원이 아니라면, 우리에 가입하여, 우리가 공동으로 노력할 수 있도록 하세요.
    연결Discord.만약 네가 우리의 다른 가이드를 보고 싶다면, 그들은 모두 그렇다.지원 요청이 있으면 [email protected]에 문의하십시오.Canonic에 대한 자세한 내용은 웹 사이트를 참조하십시오.

    좋은 웹페이지 즐겨찾기