summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorertopogo <erwin.t.pombett@gmail.com>2026-02-01 02:53:13 +0100
committerertopogo <erwin.t.pombett@gmail.com>2026-02-01 02:53:13 +0100
commitbc6f65dc9afa29fbb94038b1cfd5cbee2d87719c (patch)
tree745095c67dc674567d4e0823388252b104a2e17e
parente704383cb20e7016794ccc793eda057a609be835 (diff)
feat: mise à jour storefront + checkout
-rw-r--r--storefront/components/Layout.js154
-rw-r--r--storefront/lib/format.js22
-rw-r--r--storefront/lib/storefront.js132
-rw-r--r--storefront/pages/cart.js202
-rw-r--r--storefront/pages/checkout.js384
-rw-r--r--storefront/pages/login.js164
-rw-r--r--storefront/pages/order-confirmation.js34
-rw-r--r--storefront/pages/register.js200
8 files changed, 646 insertions, 646 deletions
diff --git a/storefront/components/Layout.js b/storefront/components/Layout.js
index dce09eb..bb3070f 100644
--- a/storefront/components/Layout.js
+++ b/storefront/components/Layout.js
@@ -1,77 +1,77 @@
-import { useEffect, useState } from "react"
-import Link from "next/link"
-import { medusaClient } from "../lib/medusa-client"
-import { clearStoredToken, getStoredToken } from "../lib/storefront"
-
-export default function Layout({ children }) {
- const [isLoggedIn, setIsLoggedIn] = useState(false)
-
- useEffect(() => {
- const token = getStoredToken()
- if (token) {
- medusaClient.setToken(token)
- setIsLoggedIn(true)
- }
- }, [])
-
- const handleLogout = () => {
- clearStoredToken()
- medusaClient.setToken(null)
- setIsLoggedIn(false)
- }
-
- return (
- <div style={{ minHeight: "100vh", fontFamily: "sans-serif", background: "#f8f8f8" }}>
- <header
- style={{
- display: "flex",
- alignItems: "center",
- justifyContent: "space-between",
- padding: "1rem 2rem",
- background: "#fff",
- borderBottom: "1px solid #e6e6e6",
- }}
- >
- <Link href="/" style={{ fontWeight: 600, textDecoration: "none", color: "#222" }}>
- Lucien-sens-bon
- </Link>
- <nav style={{ display: "flex", gap: "1rem", alignItems: "center" }}>
- <Link href="/" style={{ textDecoration: "none", color: "#444" }}>
- Boutique
- </Link>
- <Link href="/cart" style={{ textDecoration: "none", color: "#444" }}>
- Panier
- </Link>
- <Link href="/checkout" style={{ textDecoration: "none", color: "#444" }}>
- Commander
- </Link>
- {!isLoggedIn ? (
- <>
- <Link href="/register" style={{ textDecoration: "none", color: "#444" }}>
- Créer un compte
- </Link>
- <Link href="/login" style={{ textDecoration: "none", color: "#444" }}>
- Se connecter
- </Link>
- </>
- ) : (
- <button
- type="button"
- onClick={handleLogout}
- style={{
- border: "1px solid #ccc",
- background: "#fff",
- borderRadius: "6px",
- padding: "0.4rem 0.8rem",
- cursor: "pointer",
- }}
- >
- Se déconnecter
- </button>
- )}
- </nav>
- </header>
- <main style={{ padding: "2rem" }}>{children}</main>
- </div>
- )
-}
+import { useEffect, useState } from "react"
+import Link from "next/link"
+import { medusaClient } from "../lib/medusa-client"
+import { clearStoredToken, getStoredToken } from "../lib/storefront"
+
+export default function Layout({ children }) {
+ const [isLoggedIn, setIsLoggedIn] = useState(false)
+
+ useEffect(() => {
+ const token = getStoredToken()
+ if (token) {
+ medusaClient.setToken(token)
+ setIsLoggedIn(true)
+ }
+ }, [])
+
+ const handleLogout = () => {
+ clearStoredToken()
+ medusaClient.setToken(null)
+ setIsLoggedIn(false)
+ }
+
+ return (
+ <div style={{ minHeight: "100vh", fontFamily: "sans-serif", background: "#f8f8f8" }}>
+ <header
+ style={{
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "space-between",
+ padding: "1rem 2rem",
+ background: "#fff",
+ borderBottom: "1px solid #e6e6e6",
+ }}
+ >
+ <Link href="/" style={{ fontWeight: 600, textDecoration: "none", color: "#222" }}>
+ Lucien-sens-bon
+ </Link>
+ <nav style={{ display: "flex", gap: "1rem", alignItems: "center" }}>
+ <Link href="/" style={{ textDecoration: "none", color: "#444" }}>
+ Boutique
+ </Link>
+ <Link href="/cart" style={{ textDecoration: "none", color: "#444" }}>
+ Panier
+ </Link>
+ <Link href="/checkout" style={{ textDecoration: "none", color: "#444" }}>
+ Commander
+ </Link>
+ {!isLoggedIn ? (
+ <>
+ <Link href="/register" style={{ textDecoration: "none", color: "#444" }}>
+ Créer un compte
+ </Link>
+ <Link href="/login" style={{ textDecoration: "none", color: "#444" }}>
+ Se connecter
+ </Link>
+ </>
+ ) : (
+ <button
+ type="button"
+ onClick={handleLogout}
+ style={{
+ border: "1px solid #ccc",
+ background: "#fff",
+ borderRadius: "6px",
+ padding: "0.4rem 0.8rem",
+ cursor: "pointer",
+ }}
+ >
+ Se déconnecter
+ </button>
+ )}
+ </nav>
+ </header>
+ <main style={{ padding: "2rem" }}>{children}</main>
+ </div>
+ )
+}
diff --git a/storefront/lib/format.js b/storefront/lib/format.js
index 2f44c2e..9e92a8b 100644
--- a/storefront/lib/format.js
+++ b/storefront/lib/format.js
@@ -1,11 +1,11 @@
-export const formatAmount = (amount, currencyCode = "EUR") => {
- if (typeof amount !== "number") {
- return ""
- }
-
- const normalizedCurrency = currencyCode.toUpperCase()
- return new Intl.NumberFormat("fr-FR", {
- style: "currency",
- currency: normalizedCurrency,
- }).format(amount / 100)
-}
+export const formatAmount = (amount, currencyCode = "EUR") => {
+ if (typeof amount !== "number") {
+ return ""
+ }
+
+ const normalizedCurrency = currencyCode.toUpperCase()
+ return new Intl.NumberFormat("fr-FR", {
+ style: "currency",
+ currency: normalizedCurrency,
+ }).format(amount / 100)
+}
diff --git a/storefront/lib/storefront.js b/storefront/lib/storefront.js
index b6433a9..ccfe1cd 100644
--- a/storefront/lib/storefront.js
+++ b/storefront/lib/storefront.js
@@ -1,66 +1,66 @@
-export const cartStorageKey = "lsb_cart_id"
-export const tokenStorageKey = "lsb_customer_token"
-
-export const getStoredCartId = () => {
- if (typeof window === "undefined") {
- return null
- }
- return window.localStorage.getItem(cartStorageKey)
-}
-
-export const setStoredCartId = (cartId) => {
- if (typeof window === "undefined") {
- return
- }
- window.localStorage.setItem(cartStorageKey, cartId)
-}
-
-export const clearStoredCartId = () => {
- if (typeof window === "undefined") {
- return
- }
- window.localStorage.removeItem(cartStorageKey)
-}
-
-export const getStoredToken = () => {
- if (typeof window === "undefined") {
- return null
- }
- return window.localStorage.getItem(tokenStorageKey)
-}
-
-export const setStoredToken = (token) => {
- if (typeof window === "undefined") {
- return
- }
- window.localStorage.setItem(tokenStorageKey, token)
-}
-
-export const clearStoredToken = () => {
- if (typeof window === "undefined") {
- return
- }
- window.localStorage.removeItem(tokenStorageKey)
-}
-
-export const ensureCart = async (client) => {
- const storedCartId = getStoredCartId()
-
- if (storedCartId) {
- try {
- const { cart } = await client.carts.retrieve(storedCartId)
- return cart
- } catch (error) {
- clearStoredCartId()
- }
- }
-
- const { regions } = await client.regions.list()
- if (!regions?.length) {
- throw new Error("Aucune région disponible pour créer un panier.")
- }
-
- const { cart } = await client.carts.create({ region_id: regions[0].id })
- setStoredCartId(cart.id)
- return cart
-}
+export const cartStorageKey = "lsb_cart_id"
+export const tokenStorageKey = "lsb_customer_token"
+
+export const getStoredCartId = () => {
+ if (typeof window === "undefined") {
+ return null
+ }
+ return window.localStorage.getItem(cartStorageKey)
+}
+
+export const setStoredCartId = (cartId) => {
+ if (typeof window === "undefined") {
+ return
+ }
+ window.localStorage.setItem(cartStorageKey, cartId)
+}
+
+export const clearStoredCartId = () => {
+ if (typeof window === "undefined") {
+ return
+ }
+ window.localStorage.removeItem(cartStorageKey)
+}
+
+export const getStoredToken = () => {
+ if (typeof window === "undefined") {
+ return null
+ }
+ return window.localStorage.getItem(tokenStorageKey)
+}
+
+export const setStoredToken = (token) => {
+ if (typeof window === "undefined") {
+ return
+ }
+ window.localStorage.setItem(tokenStorageKey, token)
+}
+
+export const clearStoredToken = () => {
+ if (typeof window === "undefined") {
+ return
+ }
+ window.localStorage.removeItem(tokenStorageKey)
+}
+
+export const ensureCart = async (client) => {
+ const storedCartId = getStoredCartId()
+
+ if (storedCartId) {
+ try {
+ const { cart } = await client.carts.retrieve(storedCartId)
+ return cart
+ } catch (error) {
+ clearStoredCartId()
+ }
+ }
+
+ const { regions } = await client.regions.list()
+ if (!regions?.length) {
+ throw new Error("Aucune région disponible pour créer un panier.")
+ }
+
+ const { cart } = await client.carts.create({ region_id: regions[0].id })
+ setStoredCartId(cart.id)
+ return cart
+}
diff --git a/storefront/pages/cart.js b/storefront/pages/cart.js
index fa625a9..3b02b50 100644
--- a/storefront/pages/cart.js
+++ b/storefront/pages/cart.js
@@ -1,101 +1,101 @@
-import { useCallback, useEffect, useState } from "react"
-import { medusaClient } from "../lib/medusa-client"
-import { formatAmount } from "../lib/format"
-import { getStoredCartId, clearStoredCartId } from "../lib/storefront"
-
-export default function CartPage() {
- const [cart, setCart] = useState(null)
- const [status, setStatus] = useState("")
- const [isLoading, setIsLoading] = useState(true)
-
- const loadCart = useCallback(async () => {
- const storedCartId = getStoredCartId()
- if (!storedCartId) {
- setCart(null)
- setIsLoading(false)
- return
- }
-
- try {
- const { cart: fetchedCart } = await medusaClient.carts.retrieve(storedCartId)
- setCart(fetchedCart)
- } catch (error) {
- clearStoredCartId()
- setCart(null)
- } finally {
- setIsLoading(false)
- }
- }, [])
-
- useEffect(() => {
- loadCart()
- }, [loadCart])
-
- const handleRemove = async (lineItemId) => {
- if (!cart) {
- return
- }
- setStatus("")
- try {
- await medusaClient.carts.lineItems.delete(cart.id, lineItemId)
- await loadCart()
- } catch (error) {
- setStatus("Impossible de retirer l'article.")
- }
- }
-
- if (isLoading) {
- return <p>Chargement du panier...</p>
- }
-
- if (!cart || !cart.items?.length) {
- return <p>Votre panier est vide.</p>
- }
-
- return (
- <div style={{ maxWidth: "720px", margin: "0 auto" }}>
- <h1>Panier</h1>
- {status && <p>{status}</p>}
- <div style={{ display: "grid", gap: "1rem", marginTop: "1rem" }}>
- {cart.items.map((item) => (
- <div
- key={item.id}
- style={{
- border: "1px solid #ccc",
- borderRadius: "8px",
- padding: "1rem",
- display: "flex",
- justifyContent: "space-between",
- gap: "1rem",
- }}
- >
- <div>
- <strong>{item.title}</strong>
- <p>Quantité : {item.quantity}</p>
- <p>
- {formatAmount(item.unit_price, cart.region?.currency_code || "eur")}
- </p>
- </div>
- <button
- type="button"
- onClick={() => handleRemove(item.id)}
- style={{
- border: "1px solid #ccc",
- background: "#fff",
- borderRadius: "6px",
- padding: "0.4rem 0.8rem",
- cursor: "pointer",
- height: "fit-content",
- }}
- >
- Retirer
- </button>
- </div>
- ))}
- </div>
- <p style={{ marginTop: "1.5rem", fontWeight: 600 }}>
- Total : {formatAmount(cart.total, cart.region?.currency_code || "eur")}
- </p>
- </div>
- )
-}
+import { useCallback, useEffect, useState } from "react"
+import { medusaClient } from "../lib/medusa-client"
+import { formatAmount } from "../lib/format"
+import { getStoredCartId, clearStoredCartId } from "../lib/storefront"
+
+export default function CartPage() {
+ const [cart, setCart] = useState(null)
+ const [status, setStatus] = useState("")
+ const [isLoading, setIsLoading] = useState(true)
+
+ const loadCart = useCallback(async () => {
+ const storedCartId = getStoredCartId()
+ if (!storedCartId) {
+ setCart(null)
+ setIsLoading(false)
+ return
+ }
+
+ try {
+ const { cart: fetchedCart } = await medusaClient.carts.retrieve(storedCartId)
+ setCart(fetchedCart)
+ } catch (error) {
+ clearStoredCartId()
+ setCart(null)
+ } finally {
+ setIsLoading(false)
+ }
+ }, [])
+
+ useEffect(() => {
+ loadCart()
+ }, [loadCart])
+
+ const handleRemove = async (lineItemId) => {
+ if (!cart) {
+ return
+ }
+ setStatus("")
+ try {
+ await medusaClient.carts.lineItems.delete(cart.id, lineItemId)
+ await loadCart()
+ } catch (error) {
+ setStatus("Impossible de retirer l'article.")
+ }
+ }
+
+ if (isLoading) {
+ return <p>Chargement du panier...</p>
+ }
+
+ if (!cart || !cart.items?.length) {
+ return <p>Votre panier est vide.</p>
+ }
+
+ return (
+ <div style={{ maxWidth: "720px", margin: "0 auto" }}>
+ <h1>Panier</h1>
+ {status && <p>{status}</p>}
+ <div style={{ display: "grid", gap: "1rem", marginTop: "1rem" }}>
+ {cart.items.map((item) => (
+ <div
+ key={item.id}
+ style={{
+ border: "1px solid #ccc",
+ borderRadius: "8px",
+ padding: "1rem",
+ display: "flex",
+ justifyContent: "space-between",
+ gap: "1rem",
+ }}
+ >
+ <div>
+ <strong>{item.title}</strong>
+ <p>Quantité : {item.quantity}</p>
+ <p>
+ {formatAmount(item.unit_price, cart.region?.currency_code || "eur")}
+ </p>
+ </div>
+ <button
+ type="button"
+ onClick={() => handleRemove(item.id)}
+ style={{
+ border: "1px solid #ccc",
+ background: "#fff",
+ borderRadius: "6px",
+ padding: "0.4rem 0.8rem",
+ cursor: "pointer",
+ height: "fit-content",
+ }}
+ >
+ Retirer
+ </button>
+ </div>
+ ))}
+ </div>
+ <p style={{ marginTop: "1.5rem", fontWeight: 600 }}>
+ Total : {formatAmount(cart.total, cart.region?.currency_code || "eur")}
+ </p>
+ </div>
+ )
+}
diff --git a/storefront/pages/checkout.js b/storefront/pages/checkout.js
index 1970df4..9457daa 100644
--- a/storefront/pages/checkout.js
+++ b/storefront/pages/checkout.js
@@ -1,192 +1,192 @@
-import { useEffect, useState } from "react"
-import { useRouter } from "next/router"
-import { medusaClient } from "../lib/medusa-client"
-import { getStoredCartId, clearStoredCartId } from "../lib/storefront"
-
-const initialForm = {
- email: "",
- first_name: "",
- last_name: "",
- address_1: "",
- postal_code: "",
- city: "",
- country_code: "fr",
-}
-
-export default function CheckoutPage() {
- const router = useRouter()
- const [form, setForm] = useState(initialForm)
- const [status, setStatus] = useState("")
- const [isLoading, setIsLoading] = useState(false)
- const [cartId, setCartId] = useState(null)
-
- useEffect(() => {
- const storedCartId = getStoredCartId()
- setCartId(storedCartId)
- }, [])
-
- const handleChange = (event) => {
- const { name, value } = event.target
- setForm((prev) => ({ ...prev, [name]: value }))
- }
-
- const handleSubmit = async (event) => {
- event.preventDefault()
- setStatus("")
- setIsLoading(true)
-
- if (!cartId) {
- setStatus("Votre panier est vide.")
- setIsLoading(false)
- return
- }
-
- try {
- await medusaClient.carts.update(cartId, {
- email: form.email,
- shipping_address: {
- first_name: form.first_name,
- last_name: form.last_name,
- address_1: form.address_1,
- postal_code: form.postal_code,
- city: form.city,
- country_code: form.country_code,
- },
- })
-
- const { shipping_options: shippingOptions } =
- await medusaClient.shippingOptions.listCartOptions(cartId)
-
- if (!shippingOptions?.length) {
- throw new Error("Aucune option de livraison disponible.")
- }
-
- await medusaClient.carts.addShippingMethod(cartId, {
- option_id: shippingOptions[0].id,
- })
-
- const { cart: cartWithPayments } = await medusaClient.carts.createPaymentSessions(
- cartId
- )
-
- const manualSession = cartWithPayments?.payment_sessions?.find(
- (session) => session.provider_id === "manual"
- )
- const providerId =
- manualSession?.provider_id ||
- cartWithPayments?.payment_sessions?.[0]?.provider_id
-
- if (!providerId) {
- throw new Error("Aucun moyen de paiement disponible.")
- }
-
- await medusaClient.carts.setPaymentSession(cartId, { provider_id: providerId })
-
- const { type, data } = await medusaClient.carts.complete(cartId)
- if (type === "order" && data?.id) {
- clearStoredCartId()
- router.push(`/order-confirmation?order_id=${data.id}`)
- return
- }
-
- setStatus("Commande validée, mais sans numéro de commande.")
- } catch (error) {
- setStatus("Impossible de finaliser la commande.")
- } finally {
- setIsLoading(false)
- }
- }
-
- return (
- <div style={{ maxWidth: "520px", margin: "0 auto" }}>
- <h1>Finaliser la commande</h1>
- <form onSubmit={handleSubmit} style={{ display: "grid", gap: "1rem" }}>
- <label>
- Email
- <input
- name="email"
- type="email"
- value={form.email}
- onChange={handleChange}
- required
- style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
- />
- </label>
- <label>
- Prénom
- <input
- name="first_name"
- value={form.first_name}
- onChange={handleChange}
- required
- style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
- />
- </label>
- <label>
- Nom
- <input
- name="last_name"
- value={form.last_name}
- onChange={handleChange}
- required
- style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
- />
- </label>
- <label>
- Adresse
- <input
- name="address_1"
- value={form.address_1}
- onChange={handleChange}
- required
- style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
- />
- </label>
- <label>
- Code postal
- <input
- name="postal_code"
- value={form.postal_code}
- onChange={handleChange}
- required
- style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
- />
- </label>
- <label>
- Ville
- <input
- name="city"
- value={form.city}
- onChange={handleChange}
- required
- style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
- />
- </label>
- <label>
- Pays
- <input
- name="country_code"
- value={form.country_code}
- onChange={handleChange}
- required
- style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
- />
- </label>
- <button
- type="submit"
- disabled={isLoading}
- style={{
- border: "1px solid #ccc",
- background: "#fff",
- borderRadius: "6px",
- padding: "0.6rem",
- cursor: "pointer",
- }}
- >
- {isLoading ? "Validation..." : "Passer la commande"}
- </button>
- {status && <p>{status}</p>}
- </form>
- </div>
- )
-}
+import { useEffect, useState } from "react"
+import { useRouter } from "next/router"
+import { medusaClient } from "../lib/medusa-client"
+import { getStoredCartId, clearStoredCartId } from "../lib/storefront"
+
+const initialForm = {
+ email: "",
+ first_name: "",
+ last_name: "",
+ address_1: "",
+ postal_code: "",
+ city: "",
+ country_code: "fr",
+}
+
+export default function CheckoutPage() {
+ const router = useRouter()
+ const [form, setForm] = useState(initialForm)
+ const [status, setStatus] = useState("")
+ const [isLoading, setIsLoading] = useState(false)
+ const [cartId, setCartId] = useState(null)
+
+ useEffect(() => {
+ const storedCartId = getStoredCartId()
+ setCartId(storedCartId)
+ }, [])
+
+ const handleChange = (event) => {
+ const { name, value } = event.target
+ setForm((prev) => ({ ...prev, [name]: value }))
+ }
+
+ const handleSubmit = async (event) => {
+ event.preventDefault()
+ setStatus("")
+ setIsLoading(true)
+
+ if (!cartId) {
+ setStatus("Votre panier est vide.")
+ setIsLoading(false)
+ return
+ }
+
+ try {
+ await medusaClient.carts.update(cartId, {
+ email: form.email,
+ shipping_address: {
+ first_name: form.first_name,
+ last_name: form.last_name,
+ address_1: form.address_1,
+ postal_code: form.postal_code,
+ city: form.city,
+ country_code: form.country_code,
+ },
+ })
+
+ const { shipping_options: shippingOptions } =
+ await medusaClient.shippingOptions.listCartOptions(cartId)
+
+ if (!shippingOptions?.length) {
+ throw new Error("Aucune option de livraison disponible.")
+ }
+
+ await medusaClient.carts.addShippingMethod(cartId, {
+ option_id: shippingOptions[0].id,
+ })
+
+ const { cart: cartWithPayments } = await medusaClient.carts.createPaymentSessions(
+ cartId
+ )
+
+ const manualSession = cartWithPayments?.payment_sessions?.find(
+ (session) => session.provider_id === "manual"
+ )
+ const providerId =
+ manualSession?.provider_id ||
+ cartWithPayments?.payment_sessions?.[0]?.provider_id
+
+ if (!providerId) {
+ throw new Error("Aucun moyen de paiement disponible.")
+ }
+
+ await medusaClient.carts.setPaymentSession(cartId, { provider_id: providerId })
+
+ const { type, data } = await medusaClient.carts.complete(cartId)
+ if (type === "order" && data?.id) {
+ clearStoredCartId()
+ router.push(`/order-confirmation?order_id=${data.id}`)
+ return
+ }
+
+ setStatus("Commande validée, mais sans numéro de commande.")
+ } catch (error) {
+ setStatus("Impossible de finaliser la commande.")
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ return (
+ <div style={{ maxWidth: "520px", margin: "0 auto" }}>
+ <h1>Finaliser la commande</h1>
+ <form onSubmit={handleSubmit} style={{ display: "grid", gap: "1rem" }}>
+ <label>
+ Email
+ <input
+ name="email"
+ type="email"
+ value={form.email}
+ onChange={handleChange}
+ required
+ style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
+ />
+ </label>
+ <label>
+ Prénom
+ <input
+ name="first_name"
+ value={form.first_name}
+ onChange={handleChange}
+ required
+ style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
+ />
+ </label>
+ <label>
+ Nom
+ <input
+ name="last_name"
+ value={form.last_name}
+ onChange={handleChange}
+ required
+ style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
+ />
+ </label>
+ <label>
+ Adresse
+ <input
+ name="address_1"
+ value={form.address_1}
+ onChange={handleChange}
+ required
+ style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
+ />
+ </label>
+ <label>
+ Code postal
+ <input
+ name="postal_code"
+ value={form.postal_code}
+ onChange={handleChange}
+ required
+ style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
+ />
+ </label>
+ <label>
+ Ville
+ <input
+ name="city"
+ value={form.city}
+ onChange={handleChange}
+ required
+ style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
+ />
+ </label>
+ <label>
+ Pays
+ <input
+ name="country_code"
+ value={form.country_code}
+ onChange={handleChange}
+ required
+ style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
+ />
+ </label>
+ <button
+ type="submit"
+ disabled={isLoading}
+ style={{
+ border: "1px solid #ccc",
+ background: "#fff",
+ borderRadius: "6px",
+ padding: "0.6rem",
+ cursor: "pointer",
+ }}
+ >
+ {isLoading ? "Validation..." : "Passer la commande"}
+ </button>
+ {status && <p>{status}</p>}
+ </form>
+ </div>
+ )
+}
diff --git a/storefront/pages/login.js b/storefront/pages/login.js
index 033f9b5..9539a51 100644
--- a/storefront/pages/login.js
+++ b/storefront/pages/login.js
@@ -1,82 +1,82 @@
-import { useState } from "react"
-import { useRouter } from "next/router"
-import { medusaClient } from "../lib/medusa-client"
-import { setStoredToken } from "../lib/storefront"
-
-export default function LoginPage() {
- const router = useRouter()
- const [form, setForm] = useState({ email: "", password: "" })
- const [status, setStatus] = useState("")
- const [isLoading, setIsLoading] = useState(false)
-
- const handleChange = (event) => {
- const { name, value } = event.target
- setForm((prev) => ({ ...prev, [name]: value }))
- }
-
- const handleSubmit = async (event) => {
- event.preventDefault()
- setStatus("")
- setIsLoading(true)
-
- try {
- const { access_token: accessToken } = await medusaClient.auth.getToken({
- email: form.email,
- password: form.password,
- })
-
- setStoredToken(accessToken)
- medusaClient.setToken(accessToken)
- setStatus("Connexion réussie.")
- router.push("/")
- } catch (error) {
- setStatus("Identifiants invalides ou indisponibles.")
- } finally {
- setIsLoading(false)
- }
- }
-
- return (
- <div style={{ maxWidth: "420px", margin: "0 auto" }}>
- <h1>Se connecter</h1>
- <form onSubmit={handleSubmit} style={{ display: "grid", gap: "1rem" }}>
- <label>
- Email
- <input
- name="email"
- type="email"
- value={form.email}
- onChange={handleChange}
- required
- style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
- />
- </label>
- <label>
- Mot de passe
- <input
- name="password"
- type="password"
- value={form.password}
- onChange={handleChange}
- required
- style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
- />
- </label>
- <button
- type="submit"
- disabled={isLoading}
- style={{
- border: "1px solid #ccc",
- background: "#fff",
- borderRadius: "6px",
- padding: "0.6rem",
- cursor: "pointer",
- }}
- >
- {isLoading ? "Connexion..." : "Se connecter"}
- </button>
- {status && <p>{status}</p>}
- </form>
- </div>
- )
-}
+import { useState } from "react"
+import { useRouter } from "next/router"
+import { medusaClient } from "../lib/medusa-client"
+import { setStoredToken } from "../lib/storefront"
+
+export default function LoginPage() {
+ const router = useRouter()
+ const [form, setForm] = useState({ email: "", password: "" })
+ const [status, setStatus] = useState("")
+ const [isLoading, setIsLoading] = useState(false)
+
+ const handleChange = (event) => {
+ const { name, value } = event.target
+ setForm((prev) => ({ ...prev, [name]: value }))
+ }
+
+ const handleSubmit = async (event) => {
+ event.preventDefault()
+ setStatus("")
+ setIsLoading(true)
+
+ try {
+ const { access_token: accessToken } = await medusaClient.auth.getToken({
+ email: form.email,
+ password: form.password,
+ })
+
+ setStoredToken(accessToken)
+ medusaClient.setToken(accessToken)
+ setStatus("Connexion réussie.")
+ router.push("/")
+ } catch (error) {
+ setStatus("Identifiants invalides ou indisponibles.")
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ return (
+ <div style={{ maxWidth: "420px", margin: "0 auto" }}>
+ <h1>Se connecter</h1>
+ <form onSubmit={handleSubmit} style={{ display: "grid", gap: "1rem" }}>
+ <label>
+ Email
+ <input
+ name="email"
+ type="email"
+ value={form.email}
+ onChange={handleChange}
+ required
+ style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
+ />
+ </label>
+ <label>
+ Mot de passe
+ <input
+ name="password"
+ type="password"
+ value={form.password}
+ onChange={handleChange}
+ required
+ style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
+ />
+ </label>
+ <button
+ type="submit"
+ disabled={isLoading}
+ style={{
+ border: "1px solid #ccc",
+ background: "#fff",
+ borderRadius: "6px",
+ padding: "0.6rem",
+ cursor: "pointer",
+ }}
+ >
+ {isLoading ? "Connexion..." : "Se connecter"}
+ </button>
+ {status && <p>{status}</p>}
+ </form>
+ </div>
+ )
+}
diff --git a/storefront/pages/order-confirmation.js b/storefront/pages/order-confirmation.js
index 4c7930f..c1ce8df 100644
--- a/storefront/pages/order-confirmation.js
+++ b/storefront/pages/order-confirmation.js
@@ -1,17 +1,17 @@
-import { useRouter } from "next/router"
-
-export default function OrderConfirmationPage() {
- const router = useRouter()
- const { order_id: orderId } = router.query
-
- return (
- <div style={{ maxWidth: "520px", margin: "0 auto" }}>
- <h1>Merci pour votre commande</h1>
- {orderId ? (
- <p>Votre commande a bien été enregistrée : {orderId}</p>
- ) : (
- <p>Votre commande a bien été enregistrée.</p>
- )}
- </div>
- )
-}
+import { useRouter } from "next/router"
+
+export default function OrderConfirmationPage() {
+ const router = useRouter()
+ const { order_id: orderId } = router.query
+
+ return (
+ <div style={{ maxWidth: "520px", margin: "0 auto" }}>
+ <h1>Merci pour votre commande</h1>
+ {orderId ? (
+ <p>Votre commande a bien été enregistrée : {orderId}</p>
+ ) : (
+ <p>Votre commande a bien été enregistrée.</p>
+ )}
+ </div>
+ )
+}
diff --git a/storefront/pages/register.js b/storefront/pages/register.js
index 48831ea..688a09e 100644
--- a/storefront/pages/register.js
+++ b/storefront/pages/register.js
@@ -1,100 +1,100 @@
-import { useState } from "react"
-import { useRouter } from "next/router"
-import { medusaClient } from "../lib/medusa-client"
-
-export default function RegisterPage() {
- const router = useRouter()
- const [form, setForm] = useState({
- first_name: "",
- last_name: "",
- email: "",
- password: "",
- })
- const [status, setStatus] = useState("")
- const [isLoading, setIsLoading] = useState(false)
-
- const handleChange = (event) => {
- const { name, value } = event.target
- setForm((prev) => ({ ...prev, [name]: value }))
- }
-
- const handleSubmit = async (event) => {
- event.preventDefault()
- setStatus("")
- setIsLoading(true)
-
- try {
- await medusaClient.customers.create(form)
- setStatus("Compte créé. Vous pouvez vous connecter.")
- router.push("/login")
- } catch (error) {
- setStatus("Impossible de créer le compte pour le moment.")
- } finally {
- setIsLoading(false)
- }
- }
-
- return (
- <div style={{ maxWidth: "420px", margin: "0 auto" }}>
- <h1>Créer un compte</h1>
- <form onSubmit={handleSubmit} style={{ display: "grid", gap: "1rem" }}>
- <label>
- Prénom
- <input
- name="first_name"
- value={form.first_name}
- onChange={handleChange}
- required
- style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
- />
- </label>
- <label>
- Nom
- <input
- name="last_name"
- value={form.last_name}
- onChange={handleChange}
- required
- style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
- />
- </label>
- <label>
- Email
- <input
- name="email"
- type="email"
- value={form.email}
- onChange={handleChange}
- required
- style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
- />
- </label>
- <label>
- Mot de passe
- <input
- name="password"
- type="password"
- value={form.password}
- onChange={handleChange}
- required
- style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
- />
- </label>
- <button
- type="submit"
- disabled={isLoading}
- style={{
- border: "1px solid #ccc",
- background: "#fff",
- borderRadius: "6px",
- padding: "0.6rem",
- cursor: "pointer",
- }}
- >
- {isLoading ? "Création..." : "Créer mon compte"}
- </button>
- {status && <p>{status}</p>}
- </form>
- </div>
- )
-}
+import { useState } from "react"
+import { useRouter } from "next/router"
+import { medusaClient } from "../lib/medusa-client"
+
+export default function RegisterPage() {
+ const router = useRouter()
+ const [form, setForm] = useState({
+ first_name: "",
+ last_name: "",
+ email: "",
+ password: "",
+ })
+ const [status, setStatus] = useState("")
+ const [isLoading, setIsLoading] = useState(false)
+
+ const handleChange = (event) => {
+ const { name, value } = event.target
+ setForm((prev) => ({ ...prev, [name]: value }))
+ }
+
+ const handleSubmit = async (event) => {
+ event.preventDefault()
+ setStatus("")
+ setIsLoading(true)
+
+ try {
+ await medusaClient.customers.create(form)
+ setStatus("Compte créé. Vous pouvez vous connecter.")
+ router.push("/login")
+ } catch (error) {
+ setStatus("Impossible de créer le compte pour le moment.")
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ return (
+ <div style={{ maxWidth: "420px", margin: "0 auto" }}>
+ <h1>Créer un compte</h1>
+ <form onSubmit={handleSubmit} style={{ display: "grid", gap: "1rem" }}>
+ <label>
+ Prénom
+ <input
+ name="first_name"
+ value={form.first_name}
+ onChange={handleChange}
+ required
+ style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
+ />
+ </label>
+ <label>
+ Nom
+ <input
+ name="last_name"
+ value={form.last_name}
+ onChange={handleChange}
+ required
+ style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
+ />
+ </label>
+ <label>
+ Email
+ <input
+ name="email"
+ type="email"
+ value={form.email}
+ onChange={handleChange}
+ required
+ style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
+ />
+ </label>
+ <label>
+ Mot de passe
+ <input
+ name="password"
+ type="password"
+ value={form.password}
+ onChange={handleChange}
+ required
+ style={{ width: "100%", padding: "0.5rem", marginTop: "0.5rem" }}
+ />
+ </label>
+ <button
+ type="submit"
+ disabled={isLoading}
+ style={{
+ border: "1px solid #ccc",
+ background: "#fff",
+ borderRadius: "6px",
+ padding: "0.6rem",
+ cursor: "pointer",
+ }}
+ >
+ {isLoading ? "Création..." : "Créer mon compte"}
+ </button>
+ {status && <p>{status}</p>}
+ </form>
+ </div>
+ )
+}