Redirect customer after stripe flow completion

main
MiguelMLorente 2025-11-24 22:15:07 +01:00
parent 7f2624b75a
commit f95cba9042
7 changed files with 72 additions and 19 deletions

View File

@ -1,6 +1,9 @@
import "./App.css";
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 { Outlet, Route, Routes } from "react-router";
import { SignUp } from "./pages/SignUp.tsx";
@ -10,9 +13,16 @@ import { useState } from "react";
import { PreLoginPageContext } from "./context/pre-login-page-context.ts";
import { LoggedInPageContext } from "./context/logged-in-page-context.ts";
import { NotFound } from "./pages/NotFound.tsx";
import { BuyReturn } from "./pages/BuyReturn.tsx";
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 (
<ContentLayout defaultPadding maxContentWidth={500}>
@ -21,7 +31,7 @@ function App() {
<Routes>
<Route
element={
<PreLoginPageContext.Provider value={{ setUserId }}>
<PreLoginPageContext.Provider value={{ setUserId: storeUserId }}>
<Outlet />
</PreLoginPageContext.Provider>
}
@ -38,6 +48,7 @@ function App() {
>
<Route path="/signup" element={<SignUp />} />
<Route path="/buy" element={<Buy />} />
<Route path="/buy/return" element={<BuyReturn />} />
</Route>
<Route path="*" element={<NotFound />} />
</Routes>

View File

@ -16,5 +16,12 @@ export const registerUser = (name: string, password: string) =>
password,
}) as Promise<AxiosResponse<AccessResponse, unknown, {}>>;
export const startBuyFlow = (userId: string) =>
axios.post("/buy/start", { userId });
export const startBuyFlow = (userId: number, quantity: number) =>
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, {}>
>;

View File

@ -1,7 +1,7 @@
import { createContext, type Dispatch, type SetStateAction } from "react";
import { createContext } from "react";
interface PreLoginPageContextProps {
setUserId: Dispatch<SetStateAction<number | null>>;
setUserId: (id: number) => void;
}
export const PreLoginPageContext =

View File

@ -5,10 +5,18 @@ import {
Input,
SpaceBetween,
} 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 = () => {
const [quantity, setQuantity] = useState(0);
const { userId } = useContext(LoggedInPageContext)!;
const handleBuyFlow = () =>
startBuyFlow(userId, quantity).then(
(response) => (window.location.href = response.data.url),
);
return (
<Container>
<SpaceBetween size="s">
@ -18,7 +26,7 @@ export const Buy = () => {
value={quantity.toString()}
onChange={(e) => setQuantity(parseInt(e.detail.value))}
/>
<Button>Buy</Button>
<Button onClick={handleBuyFlow}>Buy</Button>
</SpaceBetween>
</Container>
);

18
src/pages/BuyReturn.tsx Normal file
View File

@ -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>
);
};

View File

@ -7,6 +7,7 @@ import {
} from "@cloudscape-design/components";
import { useState } from "react";
import { FormattedDate } from "react-intl";
import { Link } from "react-router";
export const SignUp = () => {
const [selectedDate, setSelectedDate] = useState<string | null>(null);
@ -50,10 +51,13 @@ export const SignUp = () => {
{!availableTokens && (
<Container>
<p>
You don't have any more tokens to sign up to any slot, please buy
here.
You don't have any tokens to sign up to a slot, please buy here.
</p>
<Button>Buy</Button>
<Button>
<Link to="/buy" style={{ textDecoration: "none" }}>
Buy
</Link>
</Button>
</Container>
)}
</SpaceBetween>

View File

@ -1,16 +1,21 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
const serverRoutes = ["/access", "/buy/start", "/buy/complete", "/buy/cancel"];
// https://vite.dev/config/
export default defineConfig({
server: {
proxy: {
"/access": {
target: "http://localhost:3000",
changeOrigin: true,
secure: false,
},
},
proxy: Object.fromEntries(
serverRoutes.map((key) => [
key,
{
target: "http://localhost:3000",
changeOrigin: true,
secure: false,
},
]),
),
},
plugins: [react()],
});