Magic and Stripe: Pt로 유료 회원 사이트를 만듭니다.2-반응 클라이언트
52392 단어 passwordlessmagicauthstripe
손님: 네.
유료 회원 사이트 클라이언트를 구축하는 데 필요한 주요 절차를 살펴보고 깊이 있게 살펴보겠습니다.
표준 인증 설정
로그인한 사용자 추적
우리는 React의
useContext
갈고리를 사용하여 로그인 사용자의 상태를 추적할 것입니다.App.js
에서는 전체 어플리케이션을 <UserContext.Provider>
으로 포장합니다.이렇게 하면 모든 하위 구성 요소가 우리가 만든 갈고리 (즉 const [user, setUser] = useState();
) 에 접근하여 사용자가 로그인했는지 확인하는 데 도움을 줄 수 있습니다./* File: client/src/App.js */
import React, { useState, useEffect } from "react";
import { Switch, Route, BrowserRouter as Router } from "react-router-dom";
import { UserContext } from "./lib/UserContext";
// Import UI components
import Home from "./components/home";
import PremiumContent from "./components/premium-content";
import Login from "./components/login";
import SignUp from "./components/signup";
import Profile from "./components/profile";
import Layout from "./components/layout";
// Import Magic-related things
import { magic } from "./lib/magic";
function App() {
// Create a hook to help us determine whether or not the user is logged in
const [user, setUser] = useState();
// If isLoggedIn is true, set the UserContext with user data
// Otherwise, set it to {user: null}
useEffect(() => {
setUser({ loading: true });
magic.user.isLoggedIn().then((isLoggedIn) => {
return isLoggedIn
? magic.user.getMetadata().then((userData) => setUser(userData))
: setUser({ user: null });
});
}, []);
return (
<Router>
<Switch>
<UserContext.Provider value={[user, setUser]}>
<Layout>
<Route path="/" exact component={Home} />
<Route path="/premium-content" component={PremiumContent} />
<Route path="/signup" component={SignUp} />
<Route path="/login" component={Login} />
<Route path="/profile" component={Profile} />
</Layout>
</UserContext.Provider>
</Switch>
</Router>
);
}
export default App;
참고: 사용자가 로그아웃하지 않는 한 Magic으로 로그인하면 7일 동안 인증을 유지합니다.유료 사용자 추적
우리는 또한 사용자가
useContext
갈고리를 사용하여 종신 방문 비용을 지불했는지 추적할 것이다.마찬가지로 App.js
내부에서 우리는 두 개의 새로운 상하문으로 전체 응용 프로그램을 포장했다. 그것이 바로 <LifetimeContext>
이고 그 다음은 <LifetimeAccessRequestStatusContext>
이다./* File: client/src/App.js */
import React, { useState, useEffect } from "react";
import { Switch, Route, BrowserRouter as Router } from "react-router-dom";
import { UserContext } from "./lib/UserContext";
import { LifetimeContext } from "./lib/LifetimeContext";
import { LifetimeAccessRequestStatusContext } from "./lib/LifetimeAccessRequestStatusContext";
// Import UI components
import Home from "./components/home";
import PremiumContent from "./components/premium-content";
import Login from "./components/login";
import SignUp from "./components/signup";
import Profile from "./components/profile";
import Layout from "./components/layout";
// Import Magic-related things
import { magic } from "./lib/magic";
function App() {
// Create a hook to check whether or not user has lifetime access
const [lifetimeAccess, setLifetimeAccess] = useState(false);
// Create a hook to prevent infinite loop in useEffect inside of /components/premium-content
const [
lifetimeAccessRequestStatus,
setLifetimeAccessRequestStatus,
] = useState("");
// Create a hook to help us determine whether or not the user is logged in
const [user, setUser] = useState();
// If isLoggedIn is true, set the UserContext with user data
// Otherwise, set it to {user: null}
useEffect(() => {
setUser({ loading: true });
magic.user.isLoggedIn().then((isLoggedIn) => {
return isLoggedIn
? magic.user.getMetadata().then((userData) => setUser(userData))
: setUser({ user: null });
});
}, []);
return (
<Router>
<Switch>
<UserContext.Provider value={[user, setUser]}>
<LifetimeContext.Provider value={[lifetimeAccess, setLifetimeAccess]}>
<LifetimeAccessRequestStatusContext.Provider
value={[
lifetimeAccessRequestStatus,
setLifetimeAccessRequestStatus,
]}
>
<Layout>
<Route path="/" exact component={Home} />
<Route path="/premium-content" component={PremiumContent} />
<Route path="/signup" component={SignUp} />
<Route path="/login" component={Login} />
<Route path="/profile" component={Profile} />
</Layout>
</LifetimeAccessRequestStatusContext.Provider>
</LifetimeContext.Provider>
</UserContext.Provider>
</Switch>
</Router>
);
}
export default App;
보시다시피 우리는 두 개의 새로운 갈고리를 추가했다.첫 번째 갈고리는 사용자가 평생 접근 권한을 가지고 있는지 확인하는 데 도움을 줄 것입니다.const [lifetimeAccess, setLifetimeAccess] = useState(false);
두 번째 갈고리는 an infinite loop of component re-renderings이 useEffect
내부의 /components/premium-content
으로 인해 발생하는 것을 방지하는 데 도움을 줄 것이다. const [
lifetimeAccessRequestStatus,
setLifetimeAccessRequestStatus,
] = useState("");
Magic Link Auth를 사용하여 로그인
client/src/components/login.js
에서 magic.auth.loginWithMagicLink()
은 사용자에게 전자메일을 보내는 신기한 링크를 터치한다.그것은 두 개의 매개 변수를 가진 대상을 받아들인다. 그것이 바로 email
과 선택할 수 있는 redirectURI
이다.Magic에서는 새 탭을 열고 응용 프로그램으로 사용자를 가져오도록 전자 메일 링크를 구성할 수 있습니다.리디렉션을 사용하지 않기 때문에 사용자는 원본 옵션에만 로그인할 수 있습니다.
사용자가 이메일 링크를 클릭하면 인증을 위해
didToken
을 /login
의 서버 엔드포인트로 보냅니다.만약 영패가 유효하다면, 우리는 UserContext
을 설정하여 사용자의 상태를 업데이트한 다음, 이를 설정 파일 페이지로 다시 지정합니다./* File: client/src/components/login.js */
async function handleLoginWithEmail(email) {
try {
setDisabled(true); // Disable login button to prevent multiple emails from being triggered
// Trigger Magic link to be sent to user
let didToken = await magic.auth.loginWithMagicLink({
email,
});
// Validate didToken with server
const res = await fetch(`${process.env.REACT_APP_SERVER_URL}/login`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + didToken,
},
});
if (res.status === 200) {
// Get info for the logged in user
let userMetadata = await magic.user.getMetadata();
// Set the UserContext to the now logged in user
await setUser(userMetadata);
history.push("/profile");
}
} catch (error) {
setDisabled(false); // Re-enable login button - user may have requested to edit their email
console.log(error);
}
}
Magic Link Auth 등록
우리는
Login
구성 요소(SignUp
에 위치)에서 client/src/components/signup.js
구성 요소와 거의 같은 코드를 적용할 것이다.유일한 차이점은 사용자 체험이다.사용자가 우리의 페이지에 처음 로그인했을 때, 그들은 우리의 무료 내용을 방문할 수 있다.
우리는 또한 고급 콘텐츠 페이지에서 그들에게 우리의 놀라운 점을 보여줄 수 있다.
일단 그들이 우리가 얼마나 훌륭한지 깨닫고 500달러를 지불하고 평생 통행증을 구매하기로 결정하면, 그들은 Count Me In을 클릭할 수 있다.
사용자가 로그인하지 않았기 때문에, 우리 프로그램은 그들에게 먼저 새 계정을 등록하도록 요구할 것이다.Magic 인증을 통과하면 결제 페이지로 리디렉션됩니다. 그곳에서 거래를 봉인하여 평생 놀라운 경험을 할 수 있습니다!
Magic을 사용하여 로그아웃
사용자가 로그아웃할 수 있도록
logout
구성 요소에 Header
함수를 추가합니다.logout()
은 Magic을 사용하여 사용자 세션을 종료하고 UserContext에서 사용자 정보를 지우고 사용자의 평생 방문과 평생 방문 요청 상태를 초기화하며 사용자를 로그인 페이지로 다시 지정합니다./* File: client/src/components/header.js */
const logout = () => {
magic.user.logout().then(() => {
setUser({ user: null }); // Clear user's info
setLifetimeAccess(false); // Reset user's lifetime access state
setLifetimeAccessRequestStatus(""); // Reset status of lifetime access request
history.push('/login');
});
};
결제 양식 작성
PaymentForm
에 client/src/components/payment-form.js
의 구성요소를 구축합니다.나라를 세우다
PaymentForm
구성 요소를 만들려면 먼저 지불 추적, 오류 표시, 사용자 인터페이스 관리를 위한 상태를 초기화해야 합니다./* File: client/src/components/payment-form.js */
const [succeeded, setSucceeded] = useState(false);
const [error, setError] = useState(null);
const [processing, setProcessing] = useState("");
const [disabled, setDisabled] = useState(true);
const [clientSecret, setClientSecret] = useState("");
우리는 아직 두 개의 주가 필요하다.하나는 우리가 만든 고객을 추적하는 것이다./* File: client/src/components/payment-form.js */
const [customerID, setCustomerID] = useState("");
다른 하나는 사용자가 결제에 성공했을 때 평생 접근 상태를 true로 설정하는 데 사용됩니다./* File: client/src/components/payment-form.js */
const [, setLifetimeAccess] = useContext(LifetimeContext);
Stripe에 대한 참조 저장
우리는 Stripe를 사용하여 고객의 지불을 처리하기 때문에 Stripe 라이브러리에 접근해야 합니다.Stripe의
useStripe()
과 useElements()
갈고리를 호출하여 이를 실현했습니다./* File: client/src/components/payment-form.js */
const stripe = useStripe();
const elements = useElements();
월급을 받다
PaymentForm
을 로드하면 /create-payment-intent
파일의 server.js
엔드포인트에 요청합니다.이 경로를 호출하면 스트라이프 고객과 스트라이프 PaymentIntent
이 생성됩니다.PaymentIntent
은 고객의 지불 주기를 추적하는 데 도움을 줄 것입니다.클라이언트가 반환한
data
에는 clientSecret
이 반환한 PaymentIntent
이 포함됩니다.우리는 이것으로 지불을 완성할 것이다. 그래서 우리는 setClientSecret()
으로 그것을 보존했다.data
에는 PaymentIntent
이 속한 고객의 ID도 포함됩니다.고객 정보를 업데이트할 때 이 ID가 필요하므로 setCustomerID()
으로 저장합니다./* File: client/src/components/payment-form.js */
useEffect(() => {
// Create PaymentIntent as soon as the page loads
fetch(`${process.env.REACT_APP_SERVER_URL}/create-payment-intent`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ email }),
})
.then((res) => {
return res.json();
})
.then((data) => {
setClientSecret(data.clientSecret);
setCustomerID(data.customer);
});
}, [email]);
Stripe 고객 업데이트
스트라이프 결제 거래가 성공하면 고객 ID를 서버의
/update-customer
엔드포인트로 전송하여 스트라이프 고객의 정보를 메타데이터로 업데이트하여 사용자가 평생 액세스 권한을 가지고 있는지 확인하도록 도와줍니다.이 요청이 완료되면 고객은 Premium 콘텐츠 페이지로 이동하여 콘텐츠에 집중할 수 있습니다.
/* File: client/src/components/payment-form.js */
const handleSubmit = async (ev) => {
ev.preventDefault();
setProcessing(true);
const payload = await stripe.confirmCardPayment(clientSecret, {
payment_method: {
card: elements.getElement(CardElement),
},
});
if (payload.error) {
setError(`Payment failed ${payload.error.message}`);
setProcessing(false);
} else {
setError(null);
setProcessing(false);
setSucceeded(true);
setLifetimeAccess(true);
// Update Stripe customer info to include metadata
// which will help us determine whether or not they
// are a Lifetime Access member.
fetch(`${process.env.REACT_APP_SERVER_URL}/update-customer`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ customerID }),
})
.then((res) => {
return res.json();
})
.then((data) => {
console.log("Updated Stripe customer object: ", data);
history.push("/premium-content");
});
}
};
CardElement 추가
PaymentForm
구성 요소를 완료하는 마지막 작업은 Stripe에서 제공하는 CardElement
구성 요소를 추가하는 것입니다.CardElement
은 카드 데이터를 수집하는 데 필요한 입력 필드를 가진 iframe를 삽입했다.이렇게 하면 카드 번호, 만료 날짜, CVC 및 우편 번호를 수집하는 단일 입력이 작성됩니다./* File: client/src/components/payment-form.js */
<CardElement
id="card-element"
options={cardStyle}
onChange={handleChange}
/>
결제 페이지 구성
현재 우리의
PaymentForm
모듈은 이미 준비가 되어 있으며, 그것을 수용할 Payment
모듈을 구축할 때가 되었다!구성 요소는 client/src/components/payment.js
에 있습니다.Payment
구성 요소에 대해 주의해야 할 두 가지 중요한 사항은 다음과 같습니다.user
에 설정된 UserContext
상태를 사용하십시오.Elements
, PaymentForm
, promise
을 도구로 사용하여 스트라이프 결제 양식을 정확하게 보여 줍니다./* File: client/src/components/payment.js */
import { useContext, useEffect } from "react";
import { useHistory } from "react-router";
import { UserContext } from "../lib/UserContext";
import Loading from "./loading";
export default function Payment({ Elements, PaymentForm, promise }) {
const [user] = useContext(UserContext);
const history = useHistory();
// If not loading and no user found, redirect to /login
useEffect(() => {
user && !user.loading && !user.issuer && history.push("/login");
}, [user, history]);
return (
<>
<h3 className="h3-header">
Purchase Lifetime Access Pass to Awesomeness 🤩
</h3>
<p>
Hi again {user?.loading ? <Loading /> : user?.email}! You successfully
signed up with your email. Please enter your card information below to
purchase your Lifetime Access Pass securely via Stripe:
</p>
{user?.loading ? (
<Loading />
) : (
<Elements stripe={promise}>
<PaymentForm email={user.email} />
</Elements>
)}
<style>{`
p {
margin-bottom: 15px;
}
.h3-header {
font-size: 22px;
margin: 25px 0;
}
`}</style>
</>
);
}
응용 프로그램에 지불 노선을 추가합니다.js
좋습니다.
PaymentForm
과 Payment
의 구성 요소가 완성됨에 따라 우리는 최종적으로 /payment
을 업데이트하여 사용자 경로를 client/src/App.js
페이지로 이동할 수 있습니다!우선, 우리는 줄무늬를 수입한다.
App.js
파일에 js 및 Stripe Elements UI 라이브러리를 추가합니다./* File: client/src/App.js */
import { loadStripe } from "@stripe/stripe-js";
import { Elements } from "@stripe/react-stripe-js";
그런 다음 Stripe.js
의 렌더링 외에 App.js
을 로드하여 각 렌더링에 스트라이프 객체가 다시 작성되지 않도록 합니다./* File: client/src/App.js */
const promise = loadStripe(process.env.REACT_APP_STRIPE_PK_KEY);
주의: Build the Payment Page에서 보듯이 promise
은 Payment
구성 요소에 전달되는 도구입니다. Elements
은 하위 요소인 PaymentForm
에 접근할 수 있는 권한을 제공합니다.다음은
/payment
이라는 새로운 루트를 추가합니다. 이것은 우리가 이전에 만든 Payment
구성 요소와 테이프 결제 폼을 정확하게 보여주는 데 필요한 도구를 되돌려줍니다./* File: client/src/App.js */
function App() {
...
<Route
path="/payment"
render={(props) => {
return (
<Payment
Elements={Elements}
PaymentForm={PaymentForm}
promise={promise}
/>
);
}}
/>
...
}
export default App;
다음
현재, 당신은 등록, 지불, 로그인과 취소 페이지가 어떻게 구축되었는지, 그리고 그들이 어떻게 일을 하는지 이해했고, 지금은 노드 서버가 비용을 지불하는 회원 사이트에 어떻게 동력을 제공하는지 이해할 때입니다.계속하려면 을 클릭합니다.
Reference
이 문제에 관하여(Magic and Stripe: Pt로 유료 회원 사이트를 만듭니다.2-반응 클라이언트), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/magiclabs/build-a-paid-membership-site-with-magic-and-stripe-pt-2-react-client-3j3m
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여(Magic and Stripe: Pt로 유료 회원 사이트를 만듭니다.2-반응 클라이언트), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/magiclabs/build-a-paid-membership-site-with-magic-and-stripe-pt-2-react-client-3j3m텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)