diff --git a/.changeset/violet-trainers-sleep.md b/.changeset/violet-trainers-sleep.md
new file mode 100644
index 0000000000000..fdbf82d75f616
--- /dev/null
+++ b/.changeset/violet-trainers-sleep.md
@@ -0,0 +1,7 @@
+---
+"@medusajs/admin-shared": patch
+"@medusajs/dashboard": patch
+"@medusajs/js-sdk": patch
+---
+
+feat(dashboard,js-sdk,admin-shared): add customer addresses + layout change
diff --git a/packages/admin/admin-shared/src/extensions/widgets/constants.ts b/packages/admin/admin-shared/src/extensions/widgets/constants.ts
index b4a83fc1a97cc..e45f38458bedb 100644
--- a/packages/admin/admin-shared/src/extensions/widgets/constants.ts
+++ b/packages/admin/admin-shared/src/extensions/widgets/constants.ts
@@ -10,6 +10,8 @@ const ORDER_INJECTION_ZONES = [
const CUSTOMER_INJECTION_ZONES = [
"customer.details.before",
"customer.details.after",
+ "customer.details.side.before",
+ "customer.details.side.after",
"customer.list.before",
"customer.list.after",
] as const
diff --git a/packages/admin/dashboard/src/components/common/listicle/index.ts b/packages/admin/dashboard/src/components/common/listicle/index.ts
new file mode 100644
index 0000000000000..49b9a3a3ee0ff
--- /dev/null
+++ b/packages/admin/dashboard/src/components/common/listicle/index.ts
@@ -0,0 +1 @@
+export * from "./listicle"
diff --git a/packages/admin/dashboard/src/components/common/listicle/listicle.tsx b/packages/admin/dashboard/src/components/common/listicle/listicle.tsx
new file mode 100644
index 0000000000000..05b7836d3fbf9
--- /dev/null
+++ b/packages/admin/dashboard/src/components/common/listicle/listicle.tsx
@@ -0,0 +1,34 @@
+import { Text } from "@medusajs/ui"
+import { ReactNode } from "react"
+
+export interface ListicleProps {
+ labelKey: string
+ descriptionKey: string
+ children?: ReactNode
+}
+
+export const Listicle = ({
+ labelKey,
+ descriptionKey,
+ children,
+}: ListicleProps) => {
+ return (
+
+
+
+
+
+ {labelKey}
+
+
+ {descriptionKey}
+
+
+
+ {children}
+
+
+
+
+ )
+}
diff --git a/packages/admin/dashboard/src/components/common/sidebar-link/sidebar-link.tsx b/packages/admin/dashboard/src/components/common/sidebar-link/sidebar-link.tsx
index cb2f9ffba6f2f..5da28dc2ec9ad 100644
--- a/packages/admin/dashboard/src/components/common/sidebar-link/sidebar-link.tsx
+++ b/packages/admin/dashboard/src/components/common/sidebar-link/sidebar-link.tsx
@@ -1,9 +1,9 @@
import { ReactNode } from "react"
import { Link } from "react-router-dom"
-import { IconAvatar } from "../icon-avatar"
-import { Text } from "@medusajs/ui"
import { TriangleRightMini } from "@medusajs/icons"
+import { Text } from "@medusajs/ui"
+import { IconAvatar } from "../icon-avatar"
export interface SidebarLinkProps {
to: string
diff --git a/packages/admin/dashboard/src/hooks/api/customers.tsx b/packages/admin/dashboard/src/hooks/api/customers.tsx
index 5f2ef7b66a5f1..88cd2a482e069 100644
--- a/packages/admin/dashboard/src/hooks/api/customers.tsx
+++ b/packages/admin/dashboard/src/hooks/api/customers.tsx
@@ -14,6 +14,9 @@ import { customerGroupsQueryKeys } from "./customer-groups"
const CUSTOMERS_QUERY_KEY = "customers" as const
export const customersQueryKeys = queryKeysFactory(CUSTOMERS_QUERY_KEY)
+export const customerAddressesQueryKeys = queryKeysFactory(
+ `${CUSTOMERS_QUERY_KEY}-addresses`
+)
export const useCustomer = (
id: string,
@@ -148,3 +151,113 @@ export const useBatchCustomerCustomerGroups = (
...options,
})
}
+
+export const useCreateCustomerAddress = (
+ id: string,
+ options?: UseMutationOptions<
+ HttpTypes.AdminCustomerResponse,
+ FetchError,
+ HttpTypes.AdminCreateCustomerAddress
+ >
+) => {
+ return useMutation({
+ mutationFn: (payload) => sdk.admin.customer.createAddress(id, payload),
+ onSuccess: (data, variables, context) => {
+ queryClient.invalidateQueries({ queryKey: customersQueryKeys.lists() })
+ queryClient.invalidateQueries({ queryKey: customersQueryKeys.detail(id) })
+ queryClient.invalidateQueries({
+ queryKey: customerAddressesQueryKeys.list(id),
+ })
+
+ options?.onSuccess?.(data, variables, context)
+ },
+ ...options,
+ })
+}
+
+export const useUpdateCustomerAddress = (
+ id: string,
+ addressId: string,
+ options?: UseMutationOptions<
+ HttpTypes.AdminCustomerResponse,
+ FetchError,
+ HttpTypes.AdminUpdateCustomerAddress
+ >
+) => {
+ return useMutation({
+ mutationFn: (payload) =>
+ sdk.admin.customer.updateAddress(id, addressId, payload),
+ onSuccess: (data, variables, context) => {
+ queryClient.invalidateQueries({ queryKey: customersQueryKeys.lists() })
+ queryClient.invalidateQueries({ queryKey: customersQueryKeys.detail(id) })
+ queryClient.invalidateQueries({
+ queryKey: customerAddressesQueryKeys.list(id),
+ })
+
+ options?.onSuccess?.(data, variables, context)
+ },
+ ...options,
+ })
+}
+
+export const useDeleteCustomerAddress = (
+ id: string,
+ options?: UseMutationOptions<
+ HttpTypes.AdminCustomerResponse,
+ FetchError,
+ string
+ >
+) => {
+ return useMutation({
+ mutationFn: (addressId: string) =>
+ sdk.admin.customer.deleteAddress(id, addressId),
+ onSuccess: (data, variables, context) => {
+ queryClient.invalidateQueries({ queryKey: customersQueryKeys.lists() })
+ queryClient.invalidateQueries({ queryKey: customersQueryKeys.detail(id) })
+ queryClient.invalidateQueries({
+ queryKey: customerAddressesQueryKeys.list(id),
+ })
+
+ options?.onSuccess?.(data, variables, context)
+ },
+ ...options,
+ })
+}
+
+export const useListCustomerAddresses = (
+ id: string,
+ query?: Record,
+ options?: UseQueryOptions<
+ HttpTypes.AdminCustomerResponse,
+ FetchError,
+ HttpTypes.AdminCustomerResponse,
+ QueryKey
+ >
+) => {
+ const { data, ...rest } = useQuery({
+ queryFn: () => sdk.admin.customer.listAddresses(id, query),
+ queryKey: customerAddressesQueryKeys.list(id),
+ ...options,
+ })
+
+ return { ...data, ...rest }
+}
+
+export const useCustomerAddress = (
+ id: string,
+ addressId: string,
+ options?: UseQueryOptions<
+ HttpTypes.AdminCustomerResponse,
+ FetchError,
+ HttpTypes.AdminCustomerResponse,
+ QueryKey
+ >
+) => {
+ const { data, ...rest } = useQuery({
+ queryFn: () => sdk.admin.customer.retrieveAddress(id, addressId),
+ queryKey: customerAddressesQueryKeys.detail(id),
+ ...options,
+ })
+
+ return { ...data, ...rest }
+}
diff --git a/packages/admin/dashboard/src/i18n/translations/$schema.json b/packages/admin/dashboard/src/i18n/translations/$schema.json
index 9c513134e44b9..3bc7a07fb813a 100644
--- a/packages/admin/dashboard/src/i18n/translations/$schema.json
+++ b/packages/admin/dashboard/src/i18n/translations/$schema.json
@@ -134,6 +134,9 @@
"areYouSure": {
"type": "string"
},
+ "areYouSureDescription": {
+ "type": "string"
+ },
"noRecordsFound": {
"type": "string"
},
@@ -1346,6 +1349,17 @@
"addresses": {
"type": "object",
"properties": {
+ "addressTypes": {
+ "shipping": {
+ "type": "string"
+ },
+ "billing": {
+ "type": "string"
+ }
+ },
+ "title": {
+ "type": "string"
+ },
"shippingAddress": {
"type": "object",
"properties": {
@@ -3491,6 +3505,84 @@
},
"hasAccount": {
"type": "string"
+ },
+ "addresses": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string"
+ },
+ "fields": {
+ "type": "object",
+ "properties": {
+ "addressName": {
+ "type": "string"
+ },
+ "address1": {
+ "type": "string"
+ },
+ "address2": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "province": {
+ "type": "string"
+ },
+ "postalCode": {
+ "type": "string"
+ },
+ "country": {
+ "type": "string"
+ },
+ "phone": {
+ "type": "string"
+ },
+ "company": {
+ "type": "string"
+ },
+ "countryCode": {
+ "type": "string"
+ },
+ "provinceCode": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "addressName",
+ "address1",
+ "address2",
+ "city",
+ "province",
+ "postalCode",
+ "country",
+ "phone",
+ "company",
+ "countryCode",
+ "provinceCode"
+ ],
+ "additionalProperties": false
+ },
+ "create": {
+ "type": "object",
+ "properties": {
+ "header": {
+ "type": "string"
+ },
+ "hint": {
+ "type": "string"
+ },
+ "successToast": {
+ "type": "string"
+ }
+ },
+ "required": ["header", "hint", "successToast"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["title", "create"],
+ "additionalProperties": false
}
},
"required": [
diff --git a/packages/admin/dashboard/src/i18n/translations/en.json b/packages/admin/dashboard/src/i18n/translations/en.json
index e987f8dfb2969..6729b6301e8ea 100644
--- a/packages/admin/dashboard/src/i18n/translations/en.json
+++ b/packages/admin/dashboard/src/i18n/translations/en.json
@@ -43,6 +43,7 @@
"plusCount": "+ {{count}}",
"plusCountMore": "+ {{count}} more",
"areYouSure": "Are you sure?",
+ "areYouSureDescription": "You are about to delete the {{entity}} {{title}}. This action cannot be undone.",
"noRecordsFound": "No records found",
"typeToConfirm": "Please type {val} to confirm:",
"noResultsTitle": "No results",
@@ -349,6 +350,11 @@
"backToDashboard": "Back to dashboard"
},
"addresses": {
+ "title": "Addresses",
+ "addressTypes": {
+ "shipping": "Shipping",
+ "billing": "Billing"
+ },
"shippingAddress": {
"header": "Shipping Address",
"editHeader": "Edit Shipping Address",
@@ -931,7 +937,28 @@
},
"registered": "Registered",
"guest": "Guest",
- "hasAccount": "Has account"
+ "hasAccount": "Has account",
+ "addresses": {
+ "title": "Addresses",
+ "fields": {
+ "addressName": "Address name",
+ "address1": "Address 1",
+ "address2": "Address 2",
+ "city": "City",
+ "province": "Province",
+ "postalCode": "Postal code",
+ "country": "Country",
+ "phone": "Phone",
+ "company": "Company",
+ "countryCode": "Country code",
+ "provinceCode": "Province code"
+ },
+ "create": {
+ "header": "Create Address",
+ "hint": "Create a new address for the customer.",
+ "successToast": "Address was successfully created."
+ }
+ }
},
"customerGroups": {
"domain": "Customer Groups",
diff --git a/packages/admin/dashboard/src/providers/router-provider/route-map.tsx b/packages/admin/dashboard/src/providers/router-provider/route-map.tsx
index a6213b404d267..1f4fa66764439 100644
--- a/packages/admin/dashboard/src/providers/router-provider/route-map.tsx
+++ b/packages/admin/dashboard/src/providers/router-provider/route-map.tsx
@@ -641,6 +641,11 @@ export const RouteMap: RouteObject[] = [
path: "edit",
lazy: () => import("../../routes/customers/customer-edit"),
},
+ {
+ path: "create-address",
+ lazy: () =>
+ import("../../routes/customers/customer-create-address"),
+ },
{
path: "add-customer-groups",
lazy: () =>
diff --git a/packages/admin/dashboard/src/routes/customers/customer-create-address/components/create-customer-address-form/create-customer-address-form.tsx b/packages/admin/dashboard/src/routes/customers/customer-create-address/components/create-customer-address-form/create-customer-address-form.tsx
new file mode 100644
index 0000000000000..93da3b8a25c10
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/customers/customer-create-address/components/create-customer-address-form/create-customer-address-form.tsx
@@ -0,0 +1,255 @@
+import { zodResolver } from "@hookform/resolvers/zod"
+import { Button, Heading, Input, Text, toast } from "@medusajs/ui"
+import { useForm } from "react-hook-form"
+import { useTranslation } from "react-i18next"
+import { useParams } from "react-router-dom"
+import * as zod from "zod"
+import { Form } from "../../../../../components/common/form"
+import { CountrySelect } from "../../../../../components/inputs/country-select"
+import {
+ RouteFocusModal,
+ useRouteModal,
+} from "../../../../../components/modals"
+import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
+import { useCreateCustomerAddress } from "../../../../../hooks/api/customers"
+
+const CreateCustomerAddressSchema = zod.object({
+ address_name: zod.string().min(1),
+ address_1: zod.string().min(1),
+ address_2: zod.string().optional(),
+ country_code: zod.string().min(2).max(2),
+ city: zod.string().optional(),
+ postal_code: zod.string().optional(),
+ province: zod.string().optional(),
+ company: zod.string().optional(),
+ phone: zod.string().optional(),
+})
+
+export const CreateCustomerAddressForm = () => {
+ const { t } = useTranslation()
+ const { id } = useParams()
+ const { handleSuccess } = useRouteModal()
+
+ const form = useForm>({
+ defaultValues: {
+ address_name: "",
+ address_1: "",
+ address_2: "",
+ city: "",
+ company: "",
+ country_code: "",
+ phone: "",
+ postal_code: "",
+ province: "",
+ },
+ resolver: zodResolver(CreateCustomerAddressSchema),
+ })
+
+ const { mutateAsync, isPending } = useCreateCustomerAddress(id!)
+
+ const handleSubmit = form.handleSubmit(async (values) => {
+ await mutateAsync(
+ {
+ address_name: values.address_name,
+ address_1: values.address_1,
+ address_2: values.address_2,
+ country_code: values.country_code,
+ city: values.city,
+ postal_code: values.postal_code,
+ province: values.province,
+ company: values.company,
+ phone: values.phone,
+ },
+ {
+ onSuccess: () => {
+ toast.success(t("customers.addresses.create.successToast"))
+
+ handleSuccess(`/customers/${id}`)
+ },
+ onError: (e) => {
+ toast.error(e.message)
+ },
+ }
+ )
+ })
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/packages/admin/dashboard/src/routes/customers/customer-create-address/components/create-customer-address-form/index.ts b/packages/admin/dashboard/src/routes/customers/customer-create-address/components/create-customer-address-form/index.ts
new file mode 100644
index 0000000000000..d7d23558b4392
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/customers/customer-create-address/components/create-customer-address-form/index.ts
@@ -0,0 +1 @@
+export * from "./create-customer-address-form"
diff --git a/packages/admin/dashboard/src/routes/customers/customer-create-address/customer-create-address.tsx b/packages/admin/dashboard/src/routes/customers/customer-create-address/customer-create-address.tsx
new file mode 100644
index 0000000000000..d8e3f43ce41d1
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/customers/customer-create-address/customer-create-address.tsx
@@ -0,0 +1,10 @@
+import { RouteFocusModal } from "../../../components/modals"
+import { CreateCustomerAddressForm } from "./components/create-customer-address-form"
+
+export const CustomerCreateAddress = () => {
+ return (
+
+
+
+ )
+}
diff --git a/packages/admin/dashboard/src/routes/customers/customer-create-address/index.ts b/packages/admin/dashboard/src/routes/customers/customer-create-address/index.ts
new file mode 100644
index 0000000000000..06c21ad3c2f4a
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/customers/customer-create-address/index.ts
@@ -0,0 +1 @@
+export { CustomerCreateAddress as Component } from "./customer-create-address"
diff --git a/packages/admin/dashboard/src/routes/customers/customer-detail/components/customer-address-section/customer-address-section.tsx b/packages/admin/dashboard/src/routes/customers/customer-detail/components/customer-address-section/customer-address-section.tsx
new file mode 100644
index 0000000000000..24fc5c91ce0e8
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/customers/customer-detail/components/customer-address-section/customer-address-section.tsx
@@ -0,0 +1,92 @@
+import { HttpTypes } from "@medusajs/types"
+import { Container, Heading, toast, usePrompt } from "@medusajs/ui"
+import { useTranslation } from "react-i18next"
+
+import { Trash } from "@medusajs/icons"
+import { Link, useNavigate } from "react-router-dom"
+import { ActionMenu } from "../../../../../components/common/action-menu"
+import { Listicle } from "../../../../../components/common/listicle"
+import { useDeleteCustomerAddress } from "../../../../../hooks/api/customers"
+
+type CustomerAddressSectionProps = {
+ customer: HttpTypes.AdminCustomer
+}
+
+export const CustomerAddressSection = ({
+ customer,
+}: CustomerAddressSectionProps) => {
+ const { t } = useTranslation()
+ const prompt = usePrompt()
+ const navigate = useNavigate()
+ const { mutateAsync: deleteAddress } = useDeleteCustomerAddress(customer.id)
+
+ const addresses = customer.addresses
+
+ const handleDelete = async (address: HttpTypes.AdminCustomerAddress) => {
+ const confirm = await prompt({
+ title: t("general.areYouSure"),
+ description: t("general.areYouSureDescription", {
+ entity: t("fields.address"),
+ title: address.address_name ?? "n/a",
+ }),
+ verificationInstruction: t("general.typeToConfirm"),
+ verificationText: address.address_name ?? "address",
+ confirmText: t("actions.delete"),
+ cancelText: t("actions.cancel"),
+ })
+
+ if (!confirm) {
+ return
+ }
+
+ await deleteAddress(address.id, {
+ onSuccess: () => {
+ toast.success(
+ t("general.success", { name: address.address_name ?? "address" })
+ )
+
+ navigate(`/customers/${customer.id}`, { replace: true })
+ },
+ onError: (e) => {
+ toast.error(e.message)
+ },
+ })
+ }
+
+ return (
+
+
+ {t("addresses.title")}
+
+ Add
+
+
+
+ {addresses.map((address) => {
+ return (
+
+ ,
+ label: t("actions.delete"),
+ onClick: async () => {
+ await handleDelete(address)
+ },
+ },
+ ],
+ },
+ ]}
+ />
+
+ )
+ })}
+
+ )
+}
diff --git a/packages/admin/dashboard/src/routes/customers/customer-detail/components/customer-address-section/index.ts b/packages/admin/dashboard/src/routes/customers/customer-detail/components/customer-address-section/index.ts
new file mode 100644
index 0000000000000..d3e48708939fe
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/customers/customer-detail/components/customer-address-section/index.ts
@@ -0,0 +1 @@
+export * from "./customer-address-section"
diff --git a/packages/admin/dashboard/src/routes/customers/customer-detail/customer-detail.tsx b/packages/admin/dashboard/src/routes/customers/customer-detail/customer-detail.tsx
index 4c77a5d99cb8d..916bb36d7e65f 100644
--- a/packages/admin/dashboard/src/routes/customers/customer-detail/customer-detail.tsx
+++ b/packages/admin/dashboard/src/routes/customers/customer-detail/customer-detail.tsx
@@ -1,9 +1,10 @@
import { useLoaderData, useParams } from "react-router-dom"
import { SingleColumnPageSkeleton } from "../../../components/common/skeleton"
-import { SingleColumnPage } from "../../../components/layout/pages"
+import { TwoColumnPage } from "../../../components/layout/pages"
import { useDashboardExtension } from "../../../extensions"
import { useCustomer } from "../../../hooks/api/customers"
+import { CustomerAddressSection } from "./components/customer-address-section/customer-address-section"
import { CustomerGeneralSection } from "./components/customer-general-section"
import { CustomerGroupSection } from "./components/customer-group-section"
import { CustomerOrderSection } from "./components/customer-order-section"
@@ -15,9 +16,11 @@ export const CustomerDetail = () => {
const initialData = useLoaderData() as Awaited<
ReturnType
>
- const { customer, isLoading, isError, error } = useCustomer(id!, undefined, {
- initialData,
- })
+ const { customer, isLoading, isError, error } = useCustomer(
+ id!,
+ { fields: "+*addresses" },
+ { initialData }
+ )
const { getWidgets } = useDashboardExtension()
@@ -30,19 +33,26 @@ export const CustomerDetail = () => {
}
return (
-
-
-
-
-
+
+
+
+
+
+
+
+
+
)
}
diff --git a/packages/admin/dashboard/src/routes/customers/customer-detail/loader.ts b/packages/admin/dashboard/src/routes/customers/customer-detail/loader.ts
index eebfaa84f9378..301e21403ed44 100644
--- a/packages/admin/dashboard/src/routes/customers/customer-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/customers/customer-detail/loader.ts
@@ -5,7 +5,10 @@ import { queryClient } from "../../../lib/query-client"
const customerDetailQuery = (id: string) => ({
queryKey: productsQueryKeys.detail(id),
- queryFn: async () => sdk.admin.customer.retrieve(id),
+ queryFn: async () =>
+ sdk.admin.customer.retrieve(id, {
+ fields: "+*addresses",
+ }),
})
export const customerLoader = async ({ params }: LoaderFunctionArgs) => {
diff --git a/packages/admin/dashboard/src/routes/products/product-list/components/product-list-table/product-list-table.tsx b/packages/admin/dashboard/src/routes/products/product-list/components/product-list-table/product-list-table.tsx
index 6cb2ae04bc613..533b6763a520e 100644
--- a/packages/admin/dashboard/src/routes/products/product-list/components/product-list-table/product-list-table.tsx
+++ b/packages/admin/dashboard/src/routes/products/product-list/components/product-list-table/product-list-table.tsx
@@ -33,6 +33,7 @@ export const ProductListTable = () => {
const { products, count, isLoading, isError, error } = useProducts(
{
...searchParams,
+ is_giftcard: false,
},
{
initialData,
diff --git a/packages/admin/dashboard/src/routes/products/product-list/loader.ts b/packages/admin/dashboard/src/routes/products/product-list/loader.ts
index a75c08c9d9964..60eb724f9287e 100644
--- a/packages/admin/dashboard/src/routes/products/product-list/loader.ts
+++ b/packages/admin/dashboard/src/routes/products/product-list/loader.ts
@@ -6,8 +6,13 @@ import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
const productsListQuery = () => ({
- queryKey: productsQueryKeys.list({ limit: 20, offset: 0 }),
- queryFn: async () => sdk.admin.product.list({ limit: 20, offset: 0 }),
+ queryKey: productsQueryKeys.list({
+ limit: 20,
+ offset: 0,
+ is_giftcard: false,
+ }),
+ queryFn: async () =>
+ sdk.admin.product.list({ limit: 20, offset: 0, is_giftcard: false }),
})
export const productsLoader = (client: QueryClient) => {
diff --git a/packages/core/js-sdk/src/admin/customer.ts b/packages/core/js-sdk/src/admin/customer.ts
index 4ce71c078f701..76a9729add1f0 100644
--- a/packages/core/js-sdk/src/admin/customer.ts
+++ b/packages/core/js-sdk/src/admin/customer.ts
@@ -1,7 +1,4 @@
-import {
- HttpTypes,
- SelectParams,
-} from "@medusajs/types"
+import { HttpTypes, SelectParams } from "@medusajs/types"
import { Client } from "../client"
import { ClientHeaders } from "../types"
@@ -20,12 +17,12 @@ export class Customer {
/**
* This method creates a customer. It sends a request to the
* [Create Customer](https://docs.medusajs.com/api/admin#customers_postcustomers) API route.
- *
+ *
* @param body - The customer's details.
* @param query - Configure the fields to retrieve in the customer.
* @param headers - Headers to pass in the request.
* @returns The customer's details.
- *
+ *
* @example
* sdk.admin.customer.create({
* email: "customer@gmail.com"
@@ -39,26 +36,27 @@ export class Customer {
query?: SelectParams,
headers?: ClientHeaders
) {
- return this.client.fetch<
- HttpTypes.AdminCustomerResponse
- >(`/admin/customers`, {
- method: "POST",
- headers,
- body,
- query,
- })
+ return this.client.fetch(
+ `/admin/customers`,
+ {
+ method: "POST",
+ headers,
+ body,
+ query,
+ }
+ )
}
/**
* This method updates a customer's details. It sends a request to the
* [Update Customer](https://docs.medusajs.com/api/admin#customers_postcustomersid) API route.
- *
+ *
* @param id - The customer's ID.
* @param body - The details to update of the customer.
* @param query - Configure the fields to retrieve in the customer.
* @param headers - Headers to pass in the request.
* @returns The customer's details.
- *
+ *
* @example
* sdk.admin.customer.update("cus_123", {
* first_name: "John"
@@ -88,25 +86,25 @@ export class Customer {
* This method retrieves a paginated list of customers. It sends a request to the
* [List Customers](https://docs.medusajs.com/api/admin#customers_getcustomers)
* API route.
- *
+ *
* @param queryParams - Filters and pagination configurations.
* @param headers - Headers to pass in the request.
* @returns The paginated list of customers.
- *
+ *
* @example
* To retrieve the list of customers:
- *
+ *
* ```ts
* sdk.admin.customer.list()
* .then(({ customers, count, limit, offset }) => {
* console.log(customers)
* })
* ```
- *
+ *
* To configure the pagination, pass the `limit` and `offset` query parameters.
- *
+ *
* For example, to retrieve only 10 items and skip 10 items:
- *
+ *
* ```ts
* sdk.admin.customer.list({
* limit: 10,
@@ -116,10 +114,10 @@ export class Customer {
* console.log(customers)
* })
* ```
- *
+ *
* Using the `fields` query parameter, you can specify the fields and relations to retrieve
* in each customer:
- *
+ *
* ```ts
* sdk.admin.customer.list({
* fields: "id,*groups"
@@ -128,43 +126,44 @@ export class Customer {
* console.log(customers)
* })
* ```
- *
+ *
* Learn more about the `fields` property in the [API reference](https://docs.medusajs.com/api/store#select-fields-and-relations).
*/
async list(
queryParams?: HttpTypes.AdminCustomerFilters,
headers?: ClientHeaders
) {
- return this.client.fetch<
- HttpTypes.AdminCustomerListResponse
- >(`/admin/customers`, {
- headers,
- query: queryParams,
- })
+ return this.client.fetch(
+ `/admin/customers`,
+ {
+ headers,
+ query: queryParams,
+ }
+ )
}
/**
- * This method retrieves a customer by its ID. It sends a request to the
+ * This method retrieves a customer by its ID. It sends a request to the
* [Get Customer](https://docs.medusajs.com/api/admin#customers_getcustomersid)
* API route.
- *
+ *
* @param id - The customer's ID.
* @param query - Configure the fields to retrieve in the customer.
* @param headers - Headers to pass in the request.
* @returns The customer's details.
- *
+ *
* @example
* To retrieve a customer by its ID:
- *
+ *
* ```ts
* sdk.admin.customer.retrieve("cus_123")
* .then(({ customer }) => {
* console.log(customer)
* })
* ```
- *
+ *
* To specify the fields and relations to retrieve:
- *
+ *
* ```ts
* sdk.admin.customer.retrieve("cus_123", {
* fields: "id,*groups"
@@ -173,7 +172,7 @@ export class Customer {
* console.log(customer)
* })
* ```
- *
+ *
* Learn more about the `fields` property in the [API reference](https://docs.medusajs.com/api/store#select-fields-and-relations).
*/
async retrieve(id: string, query?: SelectParams, headers?: ClientHeaders) {
@@ -187,14 +186,14 @@ export class Customer {
}
/**
- * This method deletes a customer by its ID. It sends a request to the
+ * This method deletes a customer by its ID. It sends a request to the
* [Delete Customer](https://docs.medusajs.com/api/admin#customers_deletecustomersid)
* API route.
- *
+ *
* @param id - The customer's ID.
* @param headers - Headers to pass in the request.
* @returns The deletion's details.
- *
+ *
* @example
* sdk.admin.customer.delete("cus_123")
* .then(({ deleted }) => {
@@ -244,4 +243,157 @@ export class Customer {
}
)
}
+
+ /**
+ * This method creates a customer address. It sends a request to the
+ * [Create Customer Address](https://docs.medusajs.com/api/admin#customers_postcustomersidaddresses)
+ * API route.
+ *
+ * @param id - The customer's ID.
+ * @param body - The customer address's details.
+ * @param headers - Headers to pass in the request.
+ * @returns The customer address's details.
+ *
+ * @example
+ * sdk.admin.customer.createAddress("cus_123", {
+ * address_1: "123 Main St",
+ * city: "Anytown",
+ * country_code: "US",
+ * postal_code: "12345"
+ * })
+ * .then(({ customer }) => {
+ * console.log(customer)
+ * })
+ */
+ async createAddress(
+ id: string,
+ body: HttpTypes.AdminCreateCustomerAddress,
+ headers?: ClientHeaders
+ ) {
+ return await this.client.fetch(
+ `/admin/customers/${id}/addresses`,
+ {
+ method: "POST",
+ headers,
+ body,
+ }
+ )
+ }
+
+ /**
+ * This method updates a customer address. It sends a request to the
+ * [Update Customer Address](https://docs.medusajs.com/api/admin#customers_postcustomersidaddressesaddressid)
+ * API route.
+ *
+ * @param id - The customer's ID.
+ * @param addressId - The customer address's ID.
+ * @param body - The customer address's details.
+ * @param headers - Headers to pass in the request.
+ * @returns The customer address's details.
+ *
+ * @example
+ * sdk.admin.customer.updateAddress("cus_123", "cus_addr_123", {
+ * address_1: "123 Main St",
+ * city: "Anytown",
+ * country_code: "US",
+ * postal_code: "12345"
+ * })
+ * .then(({ customer }) => {
+ * console.log(customer)
+ * })
+ */
+ async updateAddress(
+ id: string,
+ addressId: string,
+ body: HttpTypes.AdminUpdateCustomerAddress,
+ headers?: ClientHeaders
+ ) {
+ return await this.client.fetch(
+ `/admin/customers/${id}/addresses/${addressId}`,
+ {
+ method: "POST",
+ headers,
+ body,
+ }
+ )
+ }
+
+ /**
+ * This method deletes a customer address. It sends a request to the
+ * [Delete Customer Address](https://docs.medusajs.com/api/admin#customers_deletecustomersidaddressesaddressid)
+ * API route.
+ *
+ * @param id - The customer's ID.
+ * @param addressId - The customer address's ID.
+ * @param headers - Headers to pass in the request.
+ * @returns The customer address's details.
+ *
+ * @example
+ * sdk.admin.customer.deleteAddress("cus_123", "cus_addr_123")
+ * .then(({ customer }) => {
+ * console.log(customer)
+ * })
+ */
+ async deleteAddress(id: string, addressId: string, headers?: ClientHeaders) {
+ return await this.client.fetch(
+ `/admin/customers/${id}/addresses/${addressId}`,
+ {
+ method: "DELETE",
+ headers,
+ }
+ )
+ }
+
+ /**
+ * This method retrieves a customer address by its ID. It sends a request to the
+ * [Get Customer Address](https://docs.medusajs.com/api/admin#customers_getcustomersidaddressesaddressid)
+ * API route.
+ *
+ * @param id - The customer's ID.
+ * @param addressId - The customer address's ID.
+ * @param headers - Headers to pass in the request.
+ * @returns The customer address's details.
+ *
+ * @example
+ * sdk.admin.customer.retrieveAddress("cus_123", "cus_addr_123")
+ * .then(({ customer }) => {
+ * console.log(customer)
+ * })
+ */
+ async retrieveAddress(
+ id: string,
+ addressId: string,
+ headers?: ClientHeaders
+ ) {
+ return await this.client.fetch(
+ `/admin/customers/${id}/addresses/${addressId}`,
+ {
+ headers,
+ }
+ )
+ }
+
+ /**
+ * This method retrieves a list of customer addresses. It sends a request to the
+ * [List Customer Addresses](https://docs.medusajs.com/api/admin#customers_getcustomersidaddresses)
+ * API route.
+ *
+ * @param id - The customer's ID.
+ * @param headers - Headers to pass in the request.
+ * @returns The list of customer addresses.
+ *
+ * @example
+ * sdk.admin.customer.listAddresses("cus_123")
+ * .then(({ addresses }) => {
+ * console.log(addresses)
+ * })
+ */
+ async listAddresses(id: string, headers?: ClientHeaders) {
+ return await this.client.fetch(
+ `/admin/customers/${id}/addresses`,
+ {
+ headers,
+ }
+ )
+ }
}