Redirect customer after stripe flow completion
parent
7f2624b75a
commit
f95cba9042
17
src/App.tsx
17
src/App.tsx
|
|
@ -1,6 +1,9 @@
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
import { Login } from "./pages/Login.tsx";
|
import { Login } from "./pages/Login.tsx";
|
||||||
import { ContentLayout, SpaceBetween } from "@cloudscape-design/components";
|
import {
|
||||||
|
ContentLayout,
|
||||||
|
SpaceBetween
|
||||||
|
} from "@cloudscape-design/components";
|
||||||
import icon from "./paella-icon.png";
|
import icon from "./paella-icon.png";
|
||||||
import { Outlet, Route, Routes } from "react-router";
|
import { Outlet, Route, Routes } from "react-router";
|
||||||
import { SignUp } from "./pages/SignUp.tsx";
|
import { SignUp } from "./pages/SignUp.tsx";
|
||||||
|
|
@ -10,9 +13,16 @@ import { useState } from "react";
|
||||||
import { PreLoginPageContext } from "./context/pre-login-page-context.ts";
|
import { PreLoginPageContext } from "./context/pre-login-page-context.ts";
|
||||||
import { LoggedInPageContext } from "./context/logged-in-page-context.ts";
|
import { LoggedInPageContext } from "./context/logged-in-page-context.ts";
|
||||||
import { NotFound } from "./pages/NotFound.tsx";
|
import { NotFound } from "./pages/NotFound.tsx";
|
||||||
|
import { BuyReturn } from "./pages/BuyReturn.tsx";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [userId, setUserId] = useState<number | null>(null);
|
const locallyStoredUserId = window.localStorage.getItem("paysplit-user-id");
|
||||||
|
const locallyStoredUserIdAsNumber = locallyStoredUserId ? parseInt(locallyStoredUserId) : null
|
||||||
|
const [userId, setUserId] = useState<number | null>(locallyStoredUserIdAsNumber);
|
||||||
|
const storeUserId = (id: number) => {
|
||||||
|
window.localStorage.setItem("paysplit-user-id", id.toString());
|
||||||
|
setUserId(id);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContentLayout defaultPadding maxContentWidth={500}>
|
<ContentLayout defaultPadding maxContentWidth={500}>
|
||||||
|
|
@ -21,7 +31,7 @@ function App() {
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route
|
<Route
|
||||||
element={
|
element={
|
||||||
<PreLoginPageContext.Provider value={{ setUserId }}>
|
<PreLoginPageContext.Provider value={{ setUserId: storeUserId }}>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</PreLoginPageContext.Provider>
|
</PreLoginPageContext.Provider>
|
||||||
}
|
}
|
||||||
|
|
@ -38,6 +48,7 @@ function App() {
|
||||||
>
|
>
|
||||||
<Route path="/signup" element={<SignUp />} />
|
<Route path="/signup" element={<SignUp />} />
|
||||||
<Route path="/buy" element={<Buy />} />
|
<Route path="/buy" element={<Buy />} />
|
||||||
|
<Route path="/buy/return" element={<BuyReturn />} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="*" element={<NotFound />} />
|
<Route path="*" element={<NotFound />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|
|
||||||
|
|
@ -16,5 +16,12 @@ export const registerUser = (name: string, password: string) =>
|
||||||
password,
|
password,
|
||||||
}) as Promise<AxiosResponse<AccessResponse, unknown, {}>>;
|
}) as Promise<AxiosResponse<AccessResponse, unknown, {}>>;
|
||||||
|
|
||||||
export const startBuyFlow = (userId: string) =>
|
export const startBuyFlow = (userId: number, quantity: number) =>
|
||||||
axios.post("/buy/start", { userId });
|
axios.post("/buy/start", { userId, quantity }) as Promise<
|
||||||
|
AxiosResponse<{ url: string }, unknown, {}>
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const completeBuyFlow = (userId: number) =>
|
||||||
|
axios.post("/buy/complete", { userId }) as Promise<
|
||||||
|
AxiosResponse<{ url: string }, unknown, {}>
|
||||||
|
>;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { createContext, type Dispatch, type SetStateAction } from "react";
|
import { createContext } from "react";
|
||||||
|
|
||||||
interface PreLoginPageContextProps {
|
interface PreLoginPageContextProps {
|
||||||
setUserId: Dispatch<SetStateAction<number | null>>;
|
setUserId: (id: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PreLoginPageContext =
|
export const PreLoginPageContext =
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,18 @@ import {
|
||||||
Input,
|
Input,
|
||||||
SpaceBetween,
|
SpaceBetween,
|
||||||
} from "@cloudscape-design/components";
|
} from "@cloudscape-design/components";
|
||||||
import { useState } from "react";
|
import { useContext, useState } from "react";
|
||||||
|
import { startBuyFlow } from "../api/client";
|
||||||
|
import { LoggedInPageContext } from "../context/logged-in-page-context";
|
||||||
|
|
||||||
export const Buy = () => {
|
export const Buy = () => {
|
||||||
const [quantity, setQuantity] = useState(0);
|
const [quantity, setQuantity] = useState(0);
|
||||||
|
const { userId } = useContext(LoggedInPageContext)!;
|
||||||
|
const handleBuyFlow = () =>
|
||||||
|
startBuyFlow(userId, quantity).then(
|
||||||
|
(response) => (window.location.href = response.data.url),
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<SpaceBetween size="s">
|
<SpaceBetween size="s">
|
||||||
|
|
@ -18,7 +26,7 @@ export const Buy = () => {
|
||||||
value={quantity.toString()}
|
value={quantity.toString()}
|
||||||
onChange={(e) => setQuantity(parseInt(e.detail.value))}
|
onChange={(e) => setQuantity(parseInt(e.detail.value))}
|
||||||
/>
|
/>
|
||||||
<Button>Buy</Button>
|
<Button onClick={handleBuyFlow}>Buy</Button>
|
||||||
</SpaceBetween>
|
</SpaceBetween>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { Header, SpaceBetween, Spinner } from "@cloudscape-design/components";
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { completeBuyFlow } from "../api/client";
|
||||||
|
import { LoggedInPageContext } from "../context/logged-in-page-context";
|
||||||
|
|
||||||
|
export const BuyReturn = () => {
|
||||||
|
const { userId } = useContext(LoggedInPageContext)!;
|
||||||
|
completeBuyFlow(userId).then(
|
||||||
|
(response) => (window.location.href = response.data.url),
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SpaceBetween size="m" direction="horizontal">
|
||||||
|
<Spinner size="big" />
|
||||||
|
<Header>We are processing your request</Header>
|
||||||
|
</SpaceBetween>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -7,6 +7,7 @@ import {
|
||||||
} from "@cloudscape-design/components";
|
} from "@cloudscape-design/components";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { FormattedDate } from "react-intl";
|
import { FormattedDate } from "react-intl";
|
||||||
|
import { Link } from "react-router";
|
||||||
|
|
||||||
export const SignUp = () => {
|
export const SignUp = () => {
|
||||||
const [selectedDate, setSelectedDate] = useState<string | null>(null);
|
const [selectedDate, setSelectedDate] = useState<string | null>(null);
|
||||||
|
|
@ -50,10 +51,13 @@ export const SignUp = () => {
|
||||||
{!availableTokens && (
|
{!availableTokens && (
|
||||||
<Container>
|
<Container>
|
||||||
<p>
|
<p>
|
||||||
You don't have any more tokens to sign up to any slot, please buy
|
You don't have any tokens to sign up to a slot, please buy here.
|
||||||
here.
|
|
||||||
</p>
|
</p>
|
||||||
<Button>Buy</Button>
|
<Button>
|
||||||
|
<Link to="/buy" style={{ textDecoration: "none" }}>
|
||||||
|
Buy
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
</Container>
|
</Container>
|
||||||
)}
|
)}
|
||||||
</SpaceBetween>
|
</SpaceBetween>
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,21 @@
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
import react from "@vitejs/plugin-react";
|
import react from "@vitejs/plugin-react";
|
||||||
|
|
||||||
|
const serverRoutes = ["/access", "/buy/start", "/buy/complete", "/buy/cancel"];
|
||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
server: {
|
server: {
|
||||||
proxy: {
|
proxy: Object.fromEntries(
|
||||||
"/access": {
|
serverRoutes.map((key) => [
|
||||||
target: "http://localhost:3000",
|
key,
|
||||||
changeOrigin: true,
|
{
|
||||||
secure: false,
|
target: "http://localhost:3000",
|
||||||
},
|
changeOrigin: true,
|
||||||
},
|
secure: false,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue