diff --git a/src/app/[countryCode]/(main)/account/@dashboard/orders/page.tsx b/src/app/[countryCode]/(main)/account/@dashboard/orders/page.tsx
index 99a3abbdf..5d65e32bd 100644
--- a/src/app/[countryCode]/(main)/account/@dashboard/orders/page.tsx
+++ b/src/app/[countryCode]/(main)/account/@dashboard/orders/page.tsx
@@ -3,6 +3,8 @@ import { Metadata } from "next"
import OrderOverview from "@modules/account/components/order-overview"
import { notFound } from "next/navigation"
import { listOrders } from "@lib/data/orders"
+import Divider from "@modules/common/components/divider"
+import TransferRequestForm from "@modules/account/components/transfer-request-form"
export const metadata: Metadata = {
title: "Orders",
@@ -27,6 +29,8 @@ export default async function Orders() {
)
diff --git a/src/app/[countryCode]/(main)/order/confirmed/[id]/loading.tsx b/src/app/[countryCode]/(main)/order/[id]/confirmed/loading.tsx
similarity index 100%
rename from src/app/[countryCode]/(main)/order/confirmed/[id]/loading.tsx
rename to src/app/[countryCode]/(main)/order/[id]/confirmed/loading.tsx
diff --git a/src/app/[countryCode]/(main)/order/confirmed/[id]/page.tsx b/src/app/[countryCode]/(main)/order/[id]/confirmed/page.tsx
similarity index 100%
rename from src/app/[countryCode]/(main)/order/confirmed/[id]/page.tsx
rename to src/app/[countryCode]/(main)/order/[id]/confirmed/page.tsx
diff --git a/src/app/[countryCode]/(main)/order/[id]/transfer/[token]/accept/page.tsx b/src/app/[countryCode]/(main)/order/[id]/transfer/[token]/accept/page.tsx
new file mode 100644
index 000000000..943248d1a
--- /dev/null
+++ b/src/app/[countryCode]/(main)/order/[id]/transfer/[token]/accept/page.tsx
@@ -0,0 +1,41 @@
+import { acceptTransferRequest } from "@lib/data/orders"
+import { Heading, Text } from "@medusajs/ui"
+import TransferImage from "@modules/order/components/transfer-image"
+
+export default async function TransferPage({
+ params,
+}: {
+ params: { id: string; token: string }
+}) {
+ const { id, token } = params
+
+ const { success, error } = await acceptTransferRequest(id, token)
+
+ return (
+
+
+
+ {success && (
+ <>
+
+ Order transfered!
+
+
+ Order {id} has been successfully transfered to the new owner.
+
+ >
+ )}
+ {!success && (
+ <>
+
+ There was an error accepting the transfer. Please try again.
+
+ {error && (
+ Error message: {error}
+ )}
+ >
+ )}
+
+
+ )
+}
diff --git a/src/app/[countryCode]/(main)/order/[id]/transfer/[token]/decline/page.tsx b/src/app/[countryCode]/(main)/order/[id]/transfer/[token]/decline/page.tsx
new file mode 100644
index 000000000..09b5f99e1
--- /dev/null
+++ b/src/app/[countryCode]/(main)/order/[id]/transfer/[token]/decline/page.tsx
@@ -0,0 +1,41 @@
+import { declineTransferRequest } from "@lib/data/orders"
+import { Heading, Text } from "@medusajs/ui"
+import TransferImage from "@modules/order/components/transfer-image"
+
+export default async function TransferPage({
+ params,
+}: {
+ params: { id: string; token: string }
+}) {
+ const { id, token } = params
+
+ const { success, error } = await declineTransferRequest(id, token)
+
+ return (
+
+
+
+ {success && (
+ <>
+
+ Order transfer declined!
+
+
+ Transfer of order {id} has been successfully declined.
+
+ >
+ )}
+ {!success && (
+ <>
+
+ There was an error declining the transfer. Please try again.
+
+ {error && (
+ Error message: {error}
+ )}
+ >
+ )}
+
+
+ )
+}
diff --git a/src/app/[countryCode]/(main)/order/[id]/transfer/[token]/page.tsx b/src/app/[countryCode]/(main)/order/[id]/transfer/[token]/page.tsx
new file mode 100644
index 000000000..f6d440649
--- /dev/null
+++ b/src/app/[countryCode]/(main)/order/[id]/transfer/[token]/page.tsx
@@ -0,0 +1,38 @@
+import { Heading, Text } from "@medusajs/ui"
+import TransferActions from "@modules/order/components/transfer-actions"
+import TransferImage from "@modules/order/components/transfer-image"
+
+export default async function TransferPage({
+ params,
+}: {
+ params: { id: string; token: string }
+}) {
+ const { id, token } = params
+
+ return (
+
+
+
+
+ Transfer request for order {id}
+
+
+ You've received a request to transfer ownership of your order ({id}).
+ If you agree to this request, you can approve the transfer by clicking
+ the button below.
+
+
+
+ If you accept, the new owner will take over all responsibilities and
+ permissions associated with this order.
+
+
+ If you do not recognize this request or wish to retain ownership, no
+ further action is required.
+
+
+
+
+
+ )
+}
diff --git a/src/lib/data/cart.ts b/src/lib/data/cart.ts
index 4f69f09af..7a4362d93 100644
--- a/src/lib/data/cart.ts
+++ b/src/lib/data/cart.ts
@@ -371,7 +371,7 @@ export async function placeOrder() {
const countryCode =
cartRes.order.shipping_address?.country_code?.toLowerCase()
removeCartId()
- redirect(`/${countryCode}/order/confirmed/${cartRes?.order.id}`)
+ redirect(`/${countryCode}/order/${cartRes?.order.id}/confirmed`)
}
return cartRes.cart
diff --git a/src/lib/data/orders.ts b/src/lib/data/orders.ts
index 37c91904a..94c788375 100644
--- a/src/lib/data/orders.ts
+++ b/src/lib/data/orders.ts
@@ -4,6 +4,7 @@ import { sdk } from "@lib/config"
import medusaError from "@lib/util/medusa-error"
import { cache } from "react"
import { getAuthHeaders } from "./cookies"
+import { HttpTypes } from "@medusajs/types"
export const retrieveOrder = cache(async function (id: string) {
return sdk.store.order
@@ -25,3 +26,54 @@ export const listOrders = cache(async function (
.then(({ orders }) => orders)
.catch((err) => medusaError(err))
})
+
+export const createTransferRequest = async (
+ state: {
+ success: boolean
+ error: string | null
+ order: HttpTypes.StoreOrder | null
+ },
+ formData: FormData
+): Promise<{
+ success: boolean
+ error: string | null
+ order: HttpTypes.StoreOrder | null
+}> => {
+ const id = formData.get("order_id") as string
+
+ if (!id) {
+ return { success: false, error: "Order ID is required", order: null }
+ }
+
+ const headers = getAuthHeaders()
+
+ return await sdk.store.order
+ .requestTransfer(
+ id,
+ {},
+ {
+ fields: "id, email",
+ },
+ headers
+ )
+ .then(({ order }) => ({ success: true, error: null, order }))
+ .catch((err) => ({ success: false, error: err.message, order: null }))
+}
+
+export const acceptTransferRequest = async (id: string, token: string) => {
+ const headers = getAuthHeaders()
+
+ return await sdk.store.order
+ .acceptTransfer(id, { token }, {}, headers)
+ .then(({ order }) => ({ success: true, error: null, order }))
+ .catch((err) => ({ success: false, error: err.message, order: null }))
+}
+
+export const declineTransferRequest = async (id: string, token: string) => {
+ const headers = getAuthHeaders()
+
+ return await sdk.store.order
+ .declineTransfer(id, { token }, {}, headers)
+ .then(({ order }) => ({ success: true, error: null, order }))
+ .catch((err) => ({ success: false, error: err.message, order: null }))
+}
diff --git a/src/modules/account/components/transfer-request-form/index.tsx b/src/modules/account/components/transfer-request-form/index.tsx
new file mode 100644
index 000000000..66af02cda
--- /dev/null
+++ b/src/modules/account/components/transfer-request-form/index.tsx
@@ -0,0 +1,81 @@
+"use client"
+
+import { useFormState } from "react-dom"
+import { createTransferRequest } from "@lib/data/orders"
+import { Text, Heading, Input, Button, IconButton, Toaster } from "@medusajs/ui"
+import { SubmitButton } from "@modules/checkout/components/submit-button"
+import { CheckCircleMiniSolid, XCircleSolid } from "@medusajs/icons"
+import { useEffect, useState } from "react"
+
+export default function TransferRequestForm() {
+ const [showSuccess, setShowSuccess] = useState(false)
+
+ const [state, formAction] = useFormState(createTransferRequest, {
+ success: false,
+ error: null,
+ order: null,
+ })
+
+ useEffect(() => {
+ if (state.success && state.order) {
+ setShowSuccess(true)
+ }
+ }, [state.success, state.order])
+
+ return (
+
+
+
+
+ Order transfers
+
+
+ Can't find the order you are looking for?
+ Connect an order to your account.
+
+
+
+
+ {!state.success && state.error && (
+
+ {state.error}
+
+ )}
+ {showSuccess && (
+
+
+
+
+
+ Transfer for order {state.order?.id} requested
+
+
+ Transfer request email sent to {state.order?.email}
+
+
+
+
setShowSuccess(false)}
+ >
+
+
+
+ )}
+
+ )
+}
diff --git a/src/modules/order/components/transfer-actions/index.tsx b/src/modules/order/components/transfer-actions/index.tsx
new file mode 100644
index 000000000..e6148a848
--- /dev/null
+++ b/src/modules/order/components/transfer-actions/index.tsx
@@ -0,0 +1,81 @@
+"use client"
+
+import { acceptTransferRequest, declineTransferRequest } from "@lib/data/orders"
+import { Button, Text } from "@medusajs/ui"
+import { useState } from "react"
+
+type TransferStatus = "pending" | "success" | "error"
+
+const TransferActions = ({ id, token }: { id: string; token: string }) => {
+ const [errorMessage, setErrorMessage] = useState(null)
+ const [status, setStatus] = useState<{
+ accept: TransferStatus | null
+ decline: TransferStatus | null
+ } | null>({
+ accept: null,
+ decline: null,
+ })
+
+ const acceptTransfer = async () => {
+ setStatus({ accept: "pending", decline: null })
+ setErrorMessage(null)
+
+ const { success, error } = await acceptTransferRequest(id, token)
+
+ if (error) setErrorMessage(error)
+ setStatus({ accept: success ? "success" : "error", decline: null })
+ }
+
+ const declineTransfer = async () => {
+ setStatus({ accept: null, decline: "pending" })
+ setErrorMessage(null)
+
+ const { success, error } = await declineTransferRequest(id, token)
+
+ if (error) setErrorMessage(error)
+ setStatus({ accept: null, decline: success ? "success" : "error" })
+ }
+
+ return (
+
+ {status?.accept === "success" && (
+
+ Order transferred successfully!
+
+ )}
+ {status?.decline === "success" && (
+
+ Order transfer declined successfully!
+
+ )}
+ {status?.accept !== "success" && status?.decline !== "success" && (
+
+
+ Accept transfer
+
+
+ Decline transfer
+
+
+ )}
+ {errorMessage &&
{errorMessage} }
+
+ )
+}
+
+export default TransferActions
diff --git a/src/modules/order/components/transfer-image/index.tsx b/src/modules/order/components/transfer-image/index.tsx
new file mode 100644
index 000000000..aaaba5bea
--- /dev/null
+++ b/src/modules/order/components/transfer-image/index.tsx
@@ -0,0 +1,275 @@
+import { SVGProps } from "react"
+
+const TransferImage = (props: SVGProps) => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+)
+
+export default TransferImage