Skip to content

Commit f300b15

Browse files
committed
modules/product
1 parent 2dd9c40 commit f300b15

File tree

11 files changed

+170
-123
lines changed

11 files changed

+170
-123
lines changed

src/locales/us.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,28 @@ export default {
3434
"search.": "",
3535

3636
"product.select": "Select",
37-
"product.": "",
37+
"product.variant": "Select variant",
38+
"product.outof": "Out of stock",
39+
"product.addtocart": "Add to cart",
40+
"product.pricefrom": "From ",
41+
"product.priceoriginal": "Original: ",
42+
"product.info": "Product Information",
43+
"product.shipping": "Shipping & Returns",
44+
"product.material": "Material",
45+
"product.origin_country": "Country of origin",
46+
"product.type": "Type",
47+
"product.weight": "Weight",
48+
"product.dimensions": "Dimensions",
49+
"product.tags": "Tags",
50+
"product.fastdelivery_title": "Fast delivery",
51+
"product.fastdelivery_desc": "Your package will arrive in 3-5 business days at your pick up location or in the comfort of your home.",
52+
"product.simpleexchanges_title": "Simple exchanges",
53+
"product.simpleexchanges_desc": "Is the fit not quite right? No worries - we'll exchange your product for a new one.",
54+
"product.easyreturns_title": "Easy returns",
55+
"product.easyreturns_desc": "Just return your product and we'll refund your money. No questions asked – we'll do our best to make sure your return is hassle-free.",
56+
"product.related": "Related products",
57+
"product.related_sub": "You might also want to check out these products.",
58+
"product.variant_lineitem": "Variant: ",
3859
"product.": "",
3960

4061
"footer.store": "Medusa Store",

src/modules/cart/components/item/index.tsx

Lines changed: 83 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import { LineItem, Region } from "@medusajs/medusa"
44
import { Table, Text, clx } from "@medusajs/ui"
55

6+
import { I18nProviderClient, useCurrentLocale } from "../../../../locales/client"
7+
68
import CartItemSelect from "@modules/cart/components/cart-item-select"
79
import DeleteButton from "@modules/common/components/delete-button"
810
import LineItemOptions from "@modules/common/components/line-item-options"
@@ -46,78 +48,91 @@ const Item = ({ item, region, type = "full" }: ItemProps) => {
4648
}
4749

4850
return (
49-
<Table.Row className="w-full" data-testid="product-row">
50-
<Table.Cell className="!pl-0 p-4 w-24">
51-
<LocalizedClientLink
52-
href={`/products/${handle}`}
53-
className={clx("flex", {
54-
"w-16": type === "preview",
55-
"small:w-24 w-12": type === "full",
56-
})}
57-
>
58-
<Thumbnail thumbnail={item.thumbnail} size="square" />
59-
</LocalizedClientLink>
60-
</Table.Cell>
61-
62-
<Table.Cell className="text-left">
63-
<Text className="txt-medium-plus text-ui-fg-base" data-testid="product-title">{item.title}</Text>
64-
<LineItemOptions variant={item.variant} data-testid="product-variant" />
65-
</Table.Cell>
66-
67-
{type === "full" && (
68-
<Table.Cell>
69-
<div className="flex gap-2 items-center w-28">
70-
<DeleteButton id={item.id} data-testid="product-delete-button" />
71-
<CartItemSelect
72-
value={item.quantity}
73-
onChange={(value) => changeQuantity(parseInt(value.target.value))}
74-
className="w-14 h-10 p-4"
75-
data-testid="product-select-button"
76-
>
77-
{Array.from(
78-
{
79-
length: Math.min(
80-
item.variant.inventory_quantity > 0
81-
? item.variant.inventory_quantity
82-
: 10,
83-
10
84-
),
85-
},
86-
(_, i) => (
87-
<option value={i + 1} key={i}>
88-
{i + 1}
89-
</option>
90-
)
91-
)}
92-
</CartItemSelect>
93-
{updating && <Spinner />}
94-
</div>
95-
<ErrorMessage error={error} data-testid="product-error-message" />
51+
<I18nProviderClient locale={useCurrentLocale()}>
52+
<Table.Row className="w-full" data-testid="product-row">
53+
<Table.Cell className="!pl-0 p-4 w-24">
54+
<LocalizedClientLink
55+
href={`/products/${handle}`}
56+
className={clx("flex", {
57+
"w-16": type === "preview",
58+
"small:w-24 w-12": type === "full",
59+
})}
60+
>
61+
<Thumbnail thumbnail={item.thumbnail} size="square" />
62+
</LocalizedClientLink>
9663
</Table.Cell>
97-
)}
9864

99-
{type === "full" && (
100-
<Table.Cell className="hidden small:table-cell">
101-
<LineItemUnitPrice item={item} region={region} style="tight" />
65+
<Table.Cell className="text-left">
66+
<Text
67+
className="txt-medium-plus text-ui-fg-base"
68+
data-testid="product-title"
69+
>
70+
{item.title}
71+
</Text>
72+
<LineItemOptions
73+
variant={item.variant}
74+
data-testid="product-variant"
75+
/>
10276
</Table.Cell>
103-
)}
10477

105-
<Table.Cell className="!pr-0">
106-
<span
107-
className={clx("!pr-0", {
108-
"flex flex-col items-end h-full justify-center": type === "preview",
109-
})}
110-
>
111-
{type === "preview" && (
112-
<span className="flex gap-x-1 ">
113-
<Text className="text-ui-fg-muted">{item.quantity}x </Text>
114-
<LineItemUnitPrice item={item} region={region} style="tight" />
115-
</span>
116-
)}
117-
<LineItemPrice item={item} region={region} style="tight" />
118-
</span>
119-
</Table.Cell>
120-
</Table.Row>
78+
{type === "full" && (
79+
<Table.Cell>
80+
<div className="flex gap-2 items-center w-28">
81+
<DeleteButton id={item.id} data-testid="product-delete-button" />
82+
<CartItemSelect
83+
value={item.quantity}
84+
onChange={(value) =>
85+
changeQuantity(parseInt(value.target.value))
86+
}
87+
className="w-14 h-10 p-4"
88+
data-testid="product-select-button"
89+
>
90+
{Array.from(
91+
{
92+
length: Math.min(
93+
item.variant.inventory_quantity > 0
94+
? item.variant.inventory_quantity
95+
: 10,
96+
10
97+
),
98+
},
99+
(_, i) => (
100+
<option value={i + 1} key={i}>
101+
{i + 1}
102+
</option>
103+
)
104+
)}
105+
</CartItemSelect>
106+
{updating && <Spinner />}
107+
</div>
108+
<ErrorMessage error={error} data-testid="product-error-message" />
109+
</Table.Cell>
110+
)}
111+
112+
{type === "full" && (
113+
<Table.Cell className="hidden small:table-cell">
114+
<LineItemUnitPrice item={item} region={region} style="tight" />
115+
</Table.Cell>
116+
)}
117+
118+
<Table.Cell className="!pr-0">
119+
<span
120+
className={clx("!pr-0", {
121+
"flex flex-col items-end h-full justify-center":
122+
type === "preview",
123+
})}
124+
>
125+
{type === "preview" && (
126+
<span className="flex gap-x-1 ">
127+
<Text className="text-ui-fg-muted">{item.quantity}x </Text>
128+
<LineItemUnitPrice item={item} region={region} style="tight" />
129+
</span>
130+
)}
131+
<LineItemPrice item={item} region={region} style="tight" />
132+
</span>
133+
</Table.Cell>
134+
</Table.Row>
135+
</I18nProviderClient>
121136
)
122137
}
123138

src/modules/common/components/line-item-options/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ProductVariant } from "@medusajs/medusa"
22
import { Text } from "@medusajs/ui"
3+
import { useScopedI18n } from '../../../../locales/client'
34

45
type LineItemOptionsProps = {
56
variant: ProductVariant
@@ -8,9 +9,10 @@ type LineItemOptionsProps = {
89
}
910

1011
const LineItemOptions = ({ variant, 'data-testid': dataTestid, 'data-value': dataValue }: LineItemOptionsProps) => {
12+
const t = useScopedI18n("product")
1113
return (
1214
<Text data-testid={dataTestid} data-value={dataValue} className="inline-block txt-medium text-ui-fg-subtle w-full overflow-hidden text-ellipsis">
13-
Variant: {variant.title}
15+
{t("variant_lineitem")} {variant.title}
1416
</Text>
1517
)
1618
}

src/modules/products/components/mobile-actions/index.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
import { Button, clx } from "@medusajs/ui"
77
import React, { Fragment, useMemo } from "react"
88

9+
import { useI18n, useScopedI18n, I18nProviderClient } from '../../../../locales/client'
910
import useToggleState from "@lib/hooks/use-toggle-state"
1011
import ChevronDown from "@modules/common/icons/chevron-down"
1112
import X from "@modules/common/icons/x"
@@ -41,6 +42,8 @@ const MobileActions: React.FC<MobileActionsProps> = ({
4142
}) => {
4243
const { state, open, close } = useToggleState()
4344

45+
const t = useScopedI18n("product")
46+
4447
const price = getProductPrice({
4548
product: product,
4649
variantId: variant?.id,
@@ -126,10 +129,10 @@ const MobileActions: React.FC<MobileActionsProps> = ({
126129
data-testid="mobile-cart-button"
127130
>
128131
{!variant
129-
? "Select variant"
132+
? t("variant")
130133
: !inStock
131-
? "Out of stock"
132-
: "Add to cart"}
134+
? t("outof")
135+
: t("addtocart")}
133136
</Button>
134137
</div>
135138
</div>

src/modules/products/components/option-select/index.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ProductOption } from "@medusajs/medusa"
22
import { clx } from "@medusajs/ui"
33
import React from "react"
4+
import { useI18n, useScopedI18n, I18nProviderClient } from '../../../../locales/client'
45

56
import { onlyUnique } from "@lib/util/only-unique"
67

@@ -13,19 +14,20 @@ type OptionSelectProps = {
1314
"data-testid"?: string
1415
}
1516

16-
const OptionSelect: React.FC<OptionSelectProps> = ({
17+
function OptionSelect({
1718
option,
1819
current,
1920
updateOption,
2021
title,
2122
"data-testid": dataTestId,
2223
disabled,
23-
}) => {
24+
}: OptionSelectProps) {
2425
const filteredOptions = option.values.map((v) => v.value).filter(onlyUnique)
26+
const t = useScopedI18n("product")
2527

2628
return (
2729
<div className="flex flex-col gap-y-3">
28-
<span className="text-sm">Select {title}</span>
30+
<span className="text-sm">{t("select")} {title}</span>
2931
<div
3032
className="flex flex-wrap justify-between gap-2"
3133
data-testid={dataTestId}

src/modules/products/components/product-actions/index.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { isEqual } from "lodash"
77
import { useParams } from "next/navigation"
88
import { useEffect, useMemo, useRef, useState } from "react"
99

10+
import { useI18n, useScopedI18n, I18nProviderClient } from '../../../../locales/client'
1011
import { useIntersection } from "@lib/hooks/use-in-view"
1112
import { addToCart } from "@modules/cart/actions"
1213
import Divider from "@modules/common/components/divider"
@@ -36,6 +37,8 @@ export default function ProductActions({
3637
const [options, setOptions] = useState<Record<string, string>>({})
3738
const [isAdding, setIsAdding] = useState(false)
3839

40+
const t = useScopedI18n("product")
41+
3942
const countryCode = useParams().countryCode as string
4043

4144
const variants = product.variants
@@ -171,10 +174,10 @@ export default function ProductActions({
171174
data-testid="add-product-button"
172175
>
173176
{!variant
174-
? "Select variant"
177+
? t("variant")
175178
: !inStock
176-
? "Out of stock"
177-
: "Add to cart"}
179+
? t("outof")
180+
: t("addtocart")}
178181
</Button>
179182
<MobileActions
180183
product={product}

src/modules/products/components/product-price/index.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
PricedVariant,
44
} from "@medusajs/medusa/dist/types/pricing"
55
import { clx } from "@medusajs/ui"
6+
import { useI18n, useScopedI18n, I18nProviderClient } from '../../../../locales/client'
67

78
import { getProductPrice } from "@lib/util/get-product-price"
89
import { RegionInfo } from "types/global"
@@ -22,6 +23,8 @@ export default function ProductPrice({
2223
region,
2324
})
2425

26+
const t = useScopedI18n("product")
27+
2528
const selectedPrice = variant ? variantPrice : cheapestPrice
2629

2730
if (!selectedPrice) {
@@ -35,7 +38,7 @@ export default function ProductPrice({
3538
"text-ui-fg-interactive": selectedPrice.price_type === "sale",
3639
})}
3740
>
38-
{!variant && "From "}
41+
{!variant && t("pricefrom")}
3942
<span
4043
data-testid="product-price"
4144
data-value={selectedPrice.calculated_price_number}
@@ -46,7 +49,7 @@ export default function ProductPrice({
4649
{selectedPrice.price_type === "sale" && (
4750
<>
4851
<p>
49-
<span className="text-ui-fg-subtle">Original: </span>
52+
<span className="text-ui-fg-subtle">{t("priceoriginal")} </span>
5053
<span
5154
className="line-through"
5255
data-testid="original-product-price"

0 commit comments

Comments
 (0)