Skip to content

Commit

Permalink
docs: fix storefront sections in digital product recipe (#10833)
Browse files Browse the repository at this point in the history
  • Loading branch information
shahednasser authored Jan 6, 2025
1 parent f7ffa35 commit 8224466
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2590,7 +2590,10 @@ If you haven't installed the Next.js Starter storefront in the first step, refer
In `src/types/global.ts`, add the following types that you’ll use in your customizations:

```ts title="src/types/global.ts"
import { BaseProductVariant } from "@medusajs/framework/types/http/product/common"
import {
// other imports...
StoreProductVariant
} from "@medusajs/types"

// ...

Expand All @@ -2605,81 +2608,99 @@ export type DigitalProductMedia = {
fileId: string
type: "preview" | "main"
mimeType: string
digitalProduct?: DigitalProduct[]
}

export type DigitalProductPreview = DigitalProductMedia & {
url: string
}

export type VariantWithDigitalProduct = BaseProductVariant & {
export type VariantWithDigitalProduct = StoreProductVariant & {
digital_product?: DigitalProduct
}

```

### Retrieve Digital Products with Variants

To retrieve the digital products details when retrieving a product and its variants, in the `src/lib/data/products.ts` file, change the `getProductsById` and `getProductByHandle` functions to pass the digital products in the `fields` property passed to the `sdk.store.product.list` method:
To retrieve the digital products details when retrieving a product and its variants, in the `src/lib/data/products.ts` file, change the `listProducts` function to pass the digital products in the `fields` property passed to the `sdk.store.product.list` method:

export const fieldHighlights = [
["12"], ["27"]
["24"]
]

```ts title="src/lib/data/products.ts" highlights={fieldHighlights}
export const getProductsById = cache(async function ({
ids,
export const listProducts = async ({
pageParam = 1,
queryParams,
countryCode,
regionId,
}: {
ids: string[]
regionId: string
}) {
return sdk.store.product
.list(
{
// ...
fields: "*variants.calculated_price,*variants.digital_product",
}
// ...
)
// ...
})

export const getProductByHandle = cache(async function (
handle: string,
regionId: string
) {
return sdk.store.product
.list(
pageParam?: number
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductParams
countryCode?: string
regionId?: string
}): Promise<{
response: { products: HttpTypes.StoreProduct[]; count: number }
nextPage: number | null
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductParams
}> => {
// ...
return sdk.client
.fetch<{ products: HttpTypes.StoreProduct[]; count: number }>(
`/store/products`,
{
// ...
fields: "*variants.calculated_price,*variants.digital_product",
query: {
// ...
fields: "*variants.calculated_price,+variants.inventory_quantity,+metadata,+tags,*variants.calculated_price,*variants.digital_product",
}
}
// ...
)
// ...
})
}
```

When a customer views a product’s details page, digital products linked to variants are also retrieved.

### Get Digital Product Preview Links

To retrieve the links of a digital product’s preview media, add in `src/lib/data/products.ts` the following function:
To retrieve the links of a digital product’s preview media, first, add the following import at the top of `src/lib/data/products.ts`:

```ts title="src/lib/data/products.ts"
export const getDigitalProductPreview = cache(async function ({
import { DigitalProductPreview } from "../../types/global"
```

Then, add the following function at the end of the file:

```ts title="src/lib/data/products.ts"
export const getDigitalProductPreview = async function ({
id,
}: {
id: string
}) {
const { previews } = await fetch(
`${process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL}/store/digital-products/${id}/preview`, {
credentials: "include",
headers: {
"x-publishable-api-key": process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY,
},
}).then((res) => res.json())
const headers = {
...(await getAuthHeaders()),
}

const next = {
...(await getCacheOptions("products")),
}
const { previews } = await sdk.client.fetch<{
previews: DigitalProductPreview[]
}>(
`/store/digital-products/${id}/preview`,
{
headers,
next,
cache: "force-cache"
}
)

// for simplicity, return only the first preview url
// instead you can show all the preview media to the customer
return previews.length ? previews[0].url : ""
})
}
```

This function uses the API route you created in the previous section to get the preview links and return the first preview link.
Expand Down Expand Up @@ -2776,17 +2797,25 @@ Start by creating the file `src/lib/data/digital-products.ts` with the following
"use server"

import { DigitalProduct } from "../../types/global"
import { getAuthHeaders } from "./cookies"
import { sdk } from "../config"
import { getAuthHeaders, getCacheOptions } from "./cookies"

export const getCustomerDigitalProducts = async () => {
const { digital_products } = await fetch(
`${process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL}/store/customers/me/digital-products`, {
credentials: "include",
headers: {
...getAuthHeaders(),
"x-publishable-api-key": process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY,
},
}).then((res) => res.json())
const headers = {
...(await getAuthHeaders()),
}

const next = {
...(await getCacheOptions("products")),
}
const { digital_products } = await sdk.client.fetch<{
digital_products: DigitalProduct[]
}>(`/store/customers/me/digital-products`, {

headers,
next,
cache: "force-cache",
})

return digital_products as DigitalProduct[]
}
Expand All @@ -2801,7 +2830,6 @@ Then, create the file `src/modules/account/components/digital-products-list/inde

import { Table } from "@medusajs/ui"
import { DigitalProduct } from "../../../../types/global"
import { getDigitalMediaDownloadLink } from "../../../../lib/data/digital-products"

type Props = {
digitalProducts: DigitalProduct[]
Expand Down Expand Up @@ -2847,9 +2875,7 @@ export const DigitalProductsList = ({
}
```

This adds a `DigitalProductsList` component that receives a list of digital products and shows them in a table.

Each digital product’s media has a download link. You’ll implement its functionality afterwards.
This adds a `DigitalProductsList` component that receives a list of digital products and shows them in a table. Each digital product’s media has a download link. You’ll implement its functionality afterwards.

Next, create the file `src/app/[countryCode]/(main)/account/@dashboard/digital-products/page.tsx` with the following content:

Expand Down Expand Up @@ -2902,26 +2928,44 @@ const AccountNav = ({

return (
<div>
{/* Add before log out */}
<li>
<LocalizedClientLink
href="/account/digital-products"
className="flex items-center justify-between py-4 border-b border-gray-200 px-8"
data-testid="digital-products-link"
>
<div className="flex items-center gap-x-2">
<Photo />
<span>Digital Products</span>
</div>
<ChevronDown className="transform -rotate-90" />
</LocalizedClientLink>
</li>
<div className="small:hidden">
{/* ... */}
{/* Add before log out */}
<li>
<LocalizedClientLink
href="/account/digital-products"
className="flex items-center justify-between py-4 border-b border-gray-200 px-8"
data-testid="digital-products-link"
>
<div className="flex items-center gap-x-2">
<Photo />
<span>Digital Products</span>
</div>
<ChevronDown className="transform -rotate-90" />
</LocalizedClientLink>
</li>
{/* ... */}
</div>
<div className="hidden small:block">
{/* ... */}
{/* Add before log out */}
<li>
<AccountNavLink
href="/account/digital-products"
route={route!}
data-testid="digital-products-link"
>
Digital Products
</AccountNavLink>
</li>
{/* ... */}
</div>
</div>
)
}
```

You add a link to the new route before the log out tab.
You add a link to the new route before the log out tab both for small and large devices.

### Test Purchased Digital Products Page

Expand All @@ -2935,25 +2979,35 @@ To add a download link for the purchased digital products’ medias, first, add

```ts title="src/lib/data/digital-products.ts"
export const getDigitalMediaDownloadLink = async (mediaId: string) => {
const { url } = await fetch(
`${process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL}/store/customers/me/digital-products/${
mediaId
}/download`, {
credentials: "include",
const headers = {
...(await getAuthHeaders()),
}

const next = {
...(await getCacheOptions("products")),
}
const { url } = await sdk.client.fetch<{
url: string
}>(`/store/customers/me/digital-products/${mediaId}/download`, {
method: "POST",
headers: {
...getAuthHeaders(),
"x-publishable-api-key": process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY,
},
}).then((res) => res.json())
headers,
next,
cache: "force-cache",
})

return url
}
```

In this function, you send a request to the download API route you created earlier to retrieve the download URL of a purchased digital product media.

Then, in `src/modules/account/components/digital-products-list/index.tsx`, add a `handleDownload` function in the `DigitalProductsList` component:
Then, in `src/modules/account/components/digital-products-list/index.tsx`, import the `getDigitalMediaDownloadLink` at the top of the file:

```tsx title="src/modules/account/components/digital-products-list/index.tsx"
import { getDigitalMediaDownloadLink } from "../../../../lib/data/digital-products"
```

And add a `handleDownload` function in the `DigitalProductsList` component:

```tsx title="src/modules/account/components/digital-products-list/index.tsx"
const handleDownload = async (
Expand Down Expand Up @@ -2982,12 +3036,6 @@ Finally, add an `onClick` handler to the digital product medias’ link in the r

To test the latest changes out, open the purchased digital products page and click on the Download link of any media in the table. The media’s download link will open in a new page.

<Note>

The local file module provider doesn't support private uploads, so the download link won't actually be useful. Instead, use the [S3 module provider](../../../../architectural-modules/file/s3/page.mdx) in production.

</Note>

---

## Next Steps
Expand Down
2 changes: 1 addition & 1 deletion www/apps/resources/generated/edit-dates.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export const generatedEditDates = {
"app/nextjs-starter/page.mdx": "2024-12-12T12:31:16.661Z",
"app/recipes/b2b/page.mdx": "2024-10-03T13:07:44.153Z",
"app/recipes/commerce-automation/page.mdx": "2024-10-16T08:52:01.585Z",
"app/recipes/digital-products/examples/standard/page.mdx": "2025-01-03T14:38:04.333Z",
"app/recipes/digital-products/examples/standard/page.mdx": "2025-01-06T09:03:35.202Z",
"app/recipes/digital-products/page.mdx": "2024-10-03T13:07:44.147Z",
"app/recipes/ecommerce/page.mdx": "2024-10-22T11:01:01.218Z",
"app/recipes/integrate-ecommerce-stack/page.mdx": "2024-12-09T13:03:35.846Z",
Expand Down

0 comments on commit 8224466

Please sign in to comment.