@salifbiaye/create-boutique 0.1.5 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/dist/commands.js +3 -3
- package/cli/dist/create.js +5 -5
- package/cli/dist/generate.js +68 -10
- package/cli/dist/project.js +2 -0
- package/cli/dist/themes.js +5 -1
- package/package.json +1 -1
- package/templates/backend/src/lib/emails.ts +8 -1
- package/templates/backend/src/scripts/campaign-import.ts +6 -4
- package/templates/backend/src/scripts/seed.ts +15 -3
- package/templates/storefront/locales/en.json +33 -1
- package/templates/storefront/locales/fr.json +33 -1
- package/templates/storefront/package-lock.json +7 -0
- package/templates/storefront/package.json +1 -0
- package/templates/storefront/src/app/(main)/legal/[page]/page.tsx +3 -9
- package/templates/storefront/src/app/(main)/page.tsx +25 -0
- package/templates/storefront/src/app/(main)/store/page.tsx +3 -1
- package/templates/storefront/src/app/layout.tsx +9 -2
- package/templates/storefront/src/lib/boutique/config.ts +1 -0
- package/templates/storefront/src/lib/boutique/i18n-client.tsx +10 -2
- package/templates/storefront/src/lib/boutique/schema.ts +2 -0
- package/templates/storefront/src/modules/account/components/account-nav/index.tsx +50 -177
- package/templates/storefront/src/modules/account/components/address-card/add-address.tsx +2 -2
- package/templates/storefront/src/modules/account/components/address-card/edit-address-modal.tsx +2 -2
- package/templates/storefront/src/modules/account/components/overview/index.tsx +98 -143
- package/templates/storefront/src/modules/account/components/profile-billing-address/index.tsx +2 -3
- package/templates/storefront/src/modules/account/components/profile-phone/index.tsx +2 -3
- package/templates/storefront/src/modules/account/components/register/index.tsx +2 -3
- package/templates/storefront/src/modules/account/templates/account-layout.tsx +20 -24
- package/templates/storefront/src/modules/checkout/components/billing_address/index.tsx +2 -2
- package/templates/storefront/src/modules/checkout/components/shipping-address/index.tsx +2 -2
- package/templates/storefront/src/modules/common/components/phone-input/index.tsx +110 -0
- package/templates/storefront/src/modules/store/templates/index.tsx +82 -17
- package/templates/storefront/src/modules/store/templates/paginated-products.tsx +5 -0
- package/templates/storefront/src/modules/ub/campaign-blocks.tsx +1 -1
- package/templates/storefront/src/modules/ub/contact-page.tsx +78 -0
- package/templates/storefront/src/modules/ub/footer.tsx +26 -5
- package/templates/storefront/src/modules/ub/mobile-menu.tsx +49 -0
- package/templates/storefront/src/modules/ub/nav.tsx +2 -0
- package/templates/storefront/src/modules/ub/showcase.tsx +137 -0
- package/templates/storefront/src/styles/ub/account.css +199 -0
- package/templates/storefront/src/styles/ub/black-friday.css +96 -0
- package/templates/storefront/src/styles/ub/forms.css +61 -0
- package/templates/storefront/src/styles/ub/pages.css +382 -0
- package/templates/storefront/src/styles/ub/responsive.css +57 -0
- package/templates/storefront/src/styles/ub/showcase.css +85 -0
- package/templates/storefront/src/styles/ub/variants.css +64 -0
- package/templates/storefront/themes/black-friday-2/campaign.en.json +31 -0
- package/templates/storefront/themes/black-friday-2/campaign.fr.json +31 -0
- package/templates/storefront/themes/black-friday-2/theme.json +10 -0
- package/templates/storefront/themes/cyber-monday-2/campaign.en.json +31 -0
- package/templates/storefront/themes/cyber-monday-2/campaign.fr.json +31 -0
- package/templates/storefront/themes/cyber-monday-2/theme.json +10 -0
- package/templates/storefront/themes/halloween-2/campaign.en.json +31 -0
- package/templates/storefront/themes/halloween-2/campaign.fr.json +31 -0
- package/templates/storefront/themes/halloween-2/theme.json +10 -0
- package/templates/storefront/themes/noel-2/campaign.en.json +31 -0
- package/templates/storefront/themes/noel-2/campaign.fr.json +31 -0
- package/templates/storefront/themes/noel-2/theme.json +10 -0
- package/templates/storefront/themes/nouvel-an-2/campaign.en.json +31 -0
- package/templates/storefront/themes/nouvel-an-2/campaign.fr.json +31 -0
- package/templates/storefront/themes/nouvel-an-2/theme.json +10 -0
- package/templates/storefront/themes/thanksgiving-2/campaign.en.json +31 -0
- package/templates/storefront/themes/thanksgiving-2/campaign.fr.json +31 -0
- package/templates/storefront/themes/thanksgiving-2/theme.json +10 -0
|
@@ -68,6 +68,8 @@ export const themeSchema = z.object({
|
|
|
68
68
|
id: z.string().regex(SLUG),
|
|
69
69
|
name: z.string().min(1),
|
|
70
70
|
reference: z.string().optional(),
|
|
71
|
+
/** Variante : reprend la mise en page (règles CSS) de ce thème, avec la palette de styles/ub/variants.css. */
|
|
72
|
+
layout: z.string().regex(SLUG).optional(),
|
|
71
73
|
fonts: z.object({
|
|
72
74
|
head: z.enum(["inter", "jakarta", "oswald", "outfit", "poppins", "serif", "sora", "space-grotesk"]),
|
|
73
75
|
body: z.enum(["inter", "jakarta", "oswald", "outfit", "poppins", "serif", "sora", "space-grotesk"]),
|
|
@@ -1,197 +1,70 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import { T } from "@lib/boutique/i18n-client"
|
|
5
|
-
import { clx } from "@medusajs/ui"
|
|
6
4
|
import { ArrowRightOnRectangle } from "@medusajs/icons"
|
|
7
5
|
import { usePathname } from "next/navigation"
|
|
8
6
|
|
|
9
|
-
import
|
|
10
|
-
import User from "@modules/common/icons/user"
|
|
7
|
+
import LocalizedClientLink from "@modules/common/components/localized-client-link"
|
|
11
8
|
import MapPin from "@modules/common/icons/map-pin"
|
|
12
9
|
import Package from "@modules/common/icons/package"
|
|
13
|
-
import
|
|
10
|
+
import User from "@modules/common/icons/user"
|
|
11
|
+
import { Icon } from "@modules/ub/icons"
|
|
14
12
|
import { HttpTypes } from "@medusajs/types"
|
|
15
13
|
import { signout } from "@lib/data/customer"
|
|
16
14
|
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
15
|
+
const LINKS = [
|
|
16
|
+
{ href: "/account", key: "account.overview", testId: "overview-link", icon: <Icon name="home" /> },
|
|
17
|
+
{ href: "/account/profile", key: "account.profile", testId: "profile-link", icon: <User size={20} /> },
|
|
18
|
+
{ href: "/account/addresses", key: "account.addresses", testId: "addresses-link", icon: <MapPin size={20} /> },
|
|
19
|
+
{ href: "/account/orders", key: "account.orders", testId: "orders-link", icon: <Package size={20} /> },
|
|
20
|
+
]
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
/** Menu du compte : carte client (initiales, nom, e-mail) + liens avec icônes ; pastilles défilantes sur mobile. */
|
|
23
|
+
const AccountNav = ({ customer }: { customer: HttpTypes.StoreCustomer | null }) => {
|
|
24
|
+
const route = usePathname()
|
|
25
|
+
const initials = `${customer?.first_name?.[0] ?? ""}${customer?.last_name?.[0] ?? ""}`.toUpperCase() || "•"
|
|
26
|
+
const name = [customer?.first_name, customer?.last_name].filter(Boolean).join(" ")
|
|
27
27
|
|
|
28
28
|
return (
|
|
29
|
-
<
|
|
30
|
-
<div className="
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
>
|
|
37
|
-
|
|
38
|
-
<ChevronDown className="transform rotate-90" />
|
|
39
|
-
<span><T k="account.title" /></span>
|
|
40
|
-
</>
|
|
41
|
-
</LocalizedClientLink>
|
|
42
|
-
) : (
|
|
43
|
-
<>
|
|
44
|
-
<div className="text-xl-semi mb-4 px-8">
|
|
45
|
-
Hello {customer?.first_name}
|
|
46
|
-
</div>
|
|
47
|
-
<div className="text-base-regular">
|
|
48
|
-
<ul>
|
|
49
|
-
<li>
|
|
50
|
-
<LocalizedClientLink
|
|
51
|
-
href="/account/profile"
|
|
52
|
-
className="flex items-center justify-between py-4 border-b border-gray-200 px-8"
|
|
53
|
-
data-testid="profile-link"
|
|
54
|
-
>
|
|
55
|
-
<>
|
|
56
|
-
<div className="flex items-center gap-x-2">
|
|
57
|
-
<User size={20} />
|
|
58
|
-
<span><T k="account.profile" /></span>
|
|
59
|
-
</div>
|
|
60
|
-
<ChevronDown className="transform -rotate-90" />
|
|
61
|
-
</>
|
|
62
|
-
</LocalizedClientLink>
|
|
63
|
-
</li>
|
|
64
|
-
<li>
|
|
65
|
-
<LocalizedClientLink
|
|
66
|
-
href="/account/addresses"
|
|
67
|
-
className="flex items-center justify-between py-4 border-b border-gray-200 px-8"
|
|
68
|
-
data-testid="addresses-link"
|
|
69
|
-
>
|
|
70
|
-
<>
|
|
71
|
-
<div className="flex items-center gap-x-2">
|
|
72
|
-
<MapPin size={20} />
|
|
73
|
-
<span><T k="account.addresses" /></span>
|
|
74
|
-
</div>
|
|
75
|
-
<ChevronDown className="transform -rotate-90" />
|
|
76
|
-
</>
|
|
77
|
-
</LocalizedClientLink>
|
|
78
|
-
</li>
|
|
79
|
-
<li>
|
|
80
|
-
<LocalizedClientLink
|
|
81
|
-
href="/account/orders"
|
|
82
|
-
className="flex items-center justify-between py-4 border-b border-gray-200 px-8"
|
|
83
|
-
data-testid="orders-link"
|
|
84
|
-
>
|
|
85
|
-
<div className="flex items-center gap-x-2">
|
|
86
|
-
<Package size={20} />
|
|
87
|
-
<span><T k="account.orders" /></span>
|
|
88
|
-
</div>
|
|
89
|
-
<ChevronDown className="transform -rotate-90" />
|
|
90
|
-
</LocalizedClientLink>
|
|
91
|
-
</li>
|
|
92
|
-
<li>
|
|
93
|
-
<button
|
|
94
|
-
type="button"
|
|
95
|
-
className="flex items-center justify-between py-4 border-b border-gray-200 px-8 w-full"
|
|
96
|
-
onClick={handleLogout}
|
|
97
|
-
data-testid="logout-button"
|
|
98
|
-
>
|
|
99
|
-
<div className="flex items-center gap-x-2">
|
|
100
|
-
<ArrowRightOnRectangle />
|
|
101
|
-
<span><T k="account.logout" /></span>
|
|
102
|
-
</div>
|
|
103
|
-
<ChevronDown className="transform -rotate-90" />
|
|
104
|
-
</button>
|
|
105
|
-
</li>
|
|
106
|
-
</ul>
|
|
107
|
-
</div>
|
|
108
|
-
</>
|
|
109
|
-
)}
|
|
29
|
+
<aside className="ub-accnav" data-testid="account-nav">
|
|
30
|
+
<div className="ub-accnav__me">
|
|
31
|
+
<span className="ub-accnav__avatar" aria-hidden>
|
|
32
|
+
{initials}
|
|
33
|
+
</span>
|
|
34
|
+
<span className="ub-accnav__who">
|
|
35
|
+
<b>{name || <T k="account.title" />}</b>
|
|
36
|
+
{customer?.email && <small>{customer.email}</small>}
|
|
37
|
+
</span>
|
|
110
38
|
</div>
|
|
111
|
-
<
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
data-testid="overview-link"
|
|
123
|
-
>
|
|
124
|
-
<T k="account.overview" />
|
|
125
|
-
</AccountNavLink>
|
|
126
|
-
</li>
|
|
127
|
-
<li>
|
|
128
|
-
<AccountNavLink
|
|
129
|
-
href="/account/profile"
|
|
130
|
-
route={route!}
|
|
131
|
-
data-testid="profile-link"
|
|
132
|
-
>
|
|
133
|
-
<T k="account.profile" />
|
|
134
|
-
</AccountNavLink>
|
|
135
|
-
</li>
|
|
136
|
-
<li>
|
|
137
|
-
<AccountNavLink
|
|
138
|
-
href="/account/addresses"
|
|
139
|
-
route={route!}
|
|
140
|
-
data-testid="addresses-link"
|
|
39
|
+
<nav aria-label="account">
|
|
40
|
+
<ul className="ub-accnav__list">
|
|
41
|
+
{LINKS.map((l) => {
|
|
42
|
+
const active = l.href === "/account" ? route === l.href : route?.startsWith(l.href)
|
|
43
|
+
return (
|
|
44
|
+
<li key={l.href}>
|
|
45
|
+
<LocalizedClientLink
|
|
46
|
+
href={l.href}
|
|
47
|
+
className="ub-accnav__link"
|
|
48
|
+
aria-current={active ? "page" : undefined}
|
|
49
|
+
data-testid={l.testId}
|
|
141
50
|
>
|
|
142
|
-
<
|
|
143
|
-
|
|
51
|
+
<span className="ub-accnav__ic">{l.icon}</span>
|
|
52
|
+
<T k={l.key} />
|
|
53
|
+
</LocalizedClientLink>
|
|
144
54
|
</li>
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
data-testid="logout-button"
|
|
159
|
-
>
|
|
160
|
-
<T k="account.logout" />
|
|
161
|
-
</button>
|
|
162
|
-
</li>
|
|
163
|
-
</ul>
|
|
164
|
-
</div>
|
|
165
|
-
</div>
|
|
166
|
-
</div>
|
|
167
|
-
</div>
|
|
168
|
-
)
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
type AccountNavLinkProps = {
|
|
172
|
-
href: string
|
|
173
|
-
route: string
|
|
174
|
-
children: React.ReactNode
|
|
175
|
-
"data-testid"?: string
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const AccountNavLink = ({
|
|
179
|
-
href,
|
|
180
|
-
route,
|
|
181
|
-
children,
|
|
182
|
-
"data-testid": dataTestId,
|
|
183
|
-
}: AccountNavLinkProps) => {
|
|
184
|
-
const active = route === href
|
|
185
|
-
return (
|
|
186
|
-
<LocalizedClientLink
|
|
187
|
-
href={href}
|
|
188
|
-
className={clx("text-ui-fg-subtle hover:text-ui-fg-base", {
|
|
189
|
-
"text-ui-fg-base font-semibold": active,
|
|
190
|
-
})}
|
|
191
|
-
data-testid={dataTestId}
|
|
192
|
-
>
|
|
193
|
-
{children}
|
|
194
|
-
</LocalizedClientLink>
|
|
55
|
+
)
|
|
56
|
+
})}
|
|
57
|
+
<li>
|
|
58
|
+
<button type="button" className="ub-accnav__link ub-accnav__logout" onClick={() => signout()} data-testid="logout-button">
|
|
59
|
+
<span className="ub-accnav__ic">
|
|
60
|
+
<ArrowRightOnRectangle />
|
|
61
|
+
</span>
|
|
62
|
+
<T k="account.logout" />
|
|
63
|
+
</button>
|
|
64
|
+
</li>
|
|
65
|
+
</ul>
|
|
66
|
+
</nav>
|
|
67
|
+
</aside>
|
|
195
68
|
)
|
|
196
69
|
}
|
|
197
70
|
|
|
@@ -9,6 +9,7 @@ import { useEffect, useState, useActionState } from "react"
|
|
|
9
9
|
import useToggleState from "@lib/hooks/use-toggle-state"
|
|
10
10
|
import CountrySelect from "@modules/checkout/components/country-select"
|
|
11
11
|
import Input from "@modules/common/components/input"
|
|
12
|
+
import PhoneInput from "@modules/common/components/phone-input"
|
|
12
13
|
import Modal from "@modules/common/components/modal"
|
|
13
14
|
import { SubmitButton } from "@modules/checkout/components/submit-button"
|
|
14
15
|
import { HttpTypes } from "@medusajs/types"
|
|
@@ -130,10 +131,9 @@ const AddAddress = ({
|
|
|
130
131
|
autoComplete="country"
|
|
131
132
|
data-testid="country-select"
|
|
132
133
|
/>
|
|
133
|
-
<
|
|
134
|
+
<PhoneInput
|
|
134
135
|
label="form.phone"
|
|
135
136
|
name="phone"
|
|
136
|
-
autoComplete="phone"
|
|
137
137
|
data-testid="phone-input"
|
|
138
138
|
/>
|
|
139
139
|
</div>
|
package/templates/storefront/src/modules/account/components/address-card/edit-address-modal.tsx
CHANGED
|
@@ -9,6 +9,7 @@ import { Button, Heading, Text, clx } from "@medusajs/ui"
|
|
|
9
9
|
import useToggleState from "@lib/hooks/use-toggle-state"
|
|
10
10
|
import CountrySelect from "@modules/checkout/components/country-select"
|
|
11
11
|
import Input from "@modules/common/components/input"
|
|
12
|
+
import PhoneInput from "@modules/common/components/phone-input"
|
|
12
13
|
import Modal from "@modules/common/components/modal"
|
|
13
14
|
import Spinner from "@modules/common/icons/spinner"
|
|
14
15
|
import { SubmitButton } from "@modules/checkout/components/submit-button"
|
|
@@ -204,10 +205,9 @@ const EditAddress: React.FC<EditAddressProps> = ({
|
|
|
204
205
|
defaultValue={address.country_code || undefined}
|
|
205
206
|
data-testid="country-select"
|
|
206
207
|
/>
|
|
207
|
-
<
|
|
208
|
+
<PhoneInput
|
|
208
209
|
label="form.phone"
|
|
209
210
|
name="phone"
|
|
210
|
-
autoComplete="phone"
|
|
211
211
|
defaultValue={address.phone || undefined}
|
|
212
212
|
data-testid="phone-input"
|
|
213
213
|
/>
|
|
@@ -1,168 +1,123 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Container } from "@medusajs/ui"
|
|
1
|
+
import Link from "next/link"
|
|
3
2
|
|
|
4
|
-
import
|
|
5
|
-
import
|
|
3
|
+
import { getBoutique } from "@lib/boutique/config"
|
|
4
|
+
import { t } from "@lib/boutique/i18n"
|
|
6
5
|
import { convertToLocale } from "@lib/util/money"
|
|
7
6
|
import { HttpTypes } from "@medusajs/types"
|
|
7
|
+
import { Icon } from "@modules/ub/icons"
|
|
8
8
|
|
|
9
9
|
type OverviewProps = {
|
|
10
10
|
customer: HttpTypes.StoreCustomer | null
|
|
11
11
|
orders: HttpTypes.StoreOrder[] | null
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
/** Tableau de bord du compte : carte d'accueil, 3 indicateurs cliquables, commandes récentes. Composant serveur. */
|
|
14
15
|
const Overview = ({ customer, orders }: OverviewProps) => {
|
|
16
|
+
const { locale } = getBoutique()
|
|
17
|
+
const date = new Intl.DateTimeFormat(locale, { day: "numeric", month: "short", year: "numeric" })
|
|
18
|
+
const completion = getProfileCompletion(customer)
|
|
19
|
+
const stats = [
|
|
20
|
+
{ href: "/account/orders", icon: "cart" as const, value: String(orders?.length ?? 0), label: t("account.orders"), testId: "orders-count" },
|
|
21
|
+
{ href: "/account/profile", icon: "user" as const, value: `${completion}%`, label: t("account.profileDone"), testId: "customer-profile-completion", data: completion },
|
|
22
|
+
{ href: "/account/addresses", icon: "home" as const, value: String(customer?.addresses?.length || 0), label: t("account.addresses"), testId: "addresses-count", data: customer?.addresses?.length || 0 },
|
|
23
|
+
]
|
|
24
|
+
|
|
15
25
|
return (
|
|
16
|
-
<div data-testid="overview-page-wrapper">
|
|
17
|
-
<
|
|
18
|
-
<div
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
</
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
<
|
|
25
|
-
className="font-semibold"
|
|
26
|
-
data-testid="customer-email"
|
|
27
|
-
data-value={customer?.email}
|
|
28
|
-
>
|
|
26
|
+
<div className="ub-acc" data-testid="overview-page-wrapper">
|
|
27
|
+
<section className="ub-acc__hello">
|
|
28
|
+
<div>
|
|
29
|
+
<h1 className="ub-head" data-testid="welcome-message" data-value={customer?.first_name}>
|
|
30
|
+
{t("account.hello", { name: customer?.first_name ?? "" })}
|
|
31
|
+
</h1>
|
|
32
|
+
<p>
|
|
33
|
+
{t("account.signedInAs")}{" "}
|
|
34
|
+
<b data-testid="customer-email" data-value={customer?.email}>
|
|
29
35
|
{customer?.email}
|
|
30
|
-
</
|
|
31
|
-
</
|
|
36
|
+
</b>
|
|
37
|
+
</p>
|
|
32
38
|
</div>
|
|
33
|
-
<
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<h3 className="text-large-semi"><T k="account.profile" /></h3>
|
|
38
|
-
<div className="flex items-end gap-x-2">
|
|
39
|
-
<span
|
|
40
|
-
className="text-3xl-semi leading-none"
|
|
41
|
-
data-testid="customer-profile-completion"
|
|
42
|
-
data-value={getProfileCompletion(customer)}
|
|
43
|
-
>
|
|
44
|
-
{getProfileCompletion(customer)}%
|
|
45
|
-
</span>
|
|
46
|
-
<span className="uppercase text-base-regular text-ui-fg-subtle">
|
|
47
|
-
<T k="account.completed" />
|
|
48
|
-
</span>
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
39
|
+
<Link href="/store" className="ub-acc__shop">
|
|
40
|
+
{t("account.keepShopping")} <Icon name="arrowRight" />
|
|
41
|
+
</Link>
|
|
42
|
+
</section>
|
|
51
43
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
</div>
|
|
44
|
+
<ul className="ub-acc__stats">
|
|
45
|
+
{stats.map((s) => (
|
|
46
|
+
<li key={s.href}>
|
|
47
|
+
<Link href={s.href} className="ub-acc__stat">
|
|
48
|
+
<span className="ub-acc__ic">
|
|
49
|
+
<Icon name={s.icon} />
|
|
50
|
+
</span>
|
|
51
|
+
<b data-testid={s.testId} data-value={s.data ?? s.value}>
|
|
52
|
+
{s.value}
|
|
53
|
+
</b>
|
|
54
|
+
<small>{s.label}</small>
|
|
55
|
+
</Link>
|
|
56
|
+
</li>
|
|
57
|
+
))}
|
|
58
|
+
</ul>
|
|
68
59
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
<ul
|
|
74
|
-
className="flex flex-col gap-y-4"
|
|
75
|
-
data-testid="orders-wrapper"
|
|
76
|
-
>
|
|
77
|
-
{orders && orders.length > 0 ? (
|
|
78
|
-
orders.slice(0, 5).map((order) => {
|
|
79
|
-
return (
|
|
80
|
-
<li
|
|
81
|
-
key={order.id}
|
|
82
|
-
data-testid="order-wrapper"
|
|
83
|
-
data-value={order.id}
|
|
84
|
-
>
|
|
85
|
-
<LocalizedClientLink
|
|
86
|
-
href={`/account/orders/details/${order.id}`}
|
|
87
|
-
>
|
|
88
|
-
<Container className="bg-gray-50 flex justify-between items-center p-4">
|
|
89
|
-
<div className="grid grid-cols-3 grid-rows-2 text-small-regular gap-x-4 flex-1">
|
|
90
|
-
<span className="font-semibold">Date placed</span>
|
|
91
|
-
<span className="font-semibold">
|
|
92
|
-
<T k="account.orderNumber" />
|
|
93
|
-
</span>
|
|
94
|
-
<span className="font-semibold">
|
|
95
|
-
<T k="account.totalAmount" />
|
|
96
|
-
</span>
|
|
97
|
-
<span data-testid="order-created-date">
|
|
98
|
-
{new Date(order.created_at).toDateString()}
|
|
99
|
-
</span>
|
|
100
|
-
<span
|
|
101
|
-
data-testid="order-id"
|
|
102
|
-
data-value={order.display_id}
|
|
103
|
-
>
|
|
104
|
-
#{order.display_id}
|
|
105
|
-
</span>
|
|
106
|
-
<span data-testid="order-amount">
|
|
107
|
-
{convertToLocale({
|
|
108
|
-
amount: order.total,
|
|
109
|
-
currency_code: order.currency_code,
|
|
110
|
-
})}
|
|
111
|
-
</span>
|
|
112
|
-
</div>
|
|
113
|
-
<button
|
|
114
|
-
className="flex items-center justify-between"
|
|
115
|
-
data-testid="open-order-button"
|
|
116
|
-
>
|
|
117
|
-
<span className="sr-only">
|
|
118
|
-
Go to order #{order.display_id}
|
|
119
|
-
</span>
|
|
120
|
-
<ChevronDown className="-rotate-90" />
|
|
121
|
-
</button>
|
|
122
|
-
</Container>
|
|
123
|
-
</LocalizedClientLink>
|
|
124
|
-
</li>
|
|
125
|
-
)
|
|
126
|
-
})
|
|
127
|
-
) : (
|
|
128
|
-
<span data-testid="no-orders-message"><T k="account.noRecentOrders" /></span>
|
|
129
|
-
)}
|
|
130
|
-
</ul>
|
|
131
|
-
</div>
|
|
132
|
-
</div>
|
|
60
|
+
{completion < 100 && (
|
|
61
|
+
<div className="ub-acc__progress">
|
|
62
|
+
<span>{t("account.completeProfile")}</span>
|
|
63
|
+
<i style={{ ["--p" as string]: `${completion}%` }} />
|
|
133
64
|
</div>
|
|
134
|
-
|
|
65
|
+
)}
|
|
66
|
+
|
|
67
|
+
<section>
|
|
68
|
+
<div className="ub-acc__head">
|
|
69
|
+
<h2 className="ub-head">{t("account.recentOrders")}</h2>
|
|
70
|
+
{!!orders?.length && (
|
|
71
|
+
<Link href="/account/orders" className="ub-acc__more">
|
|
72
|
+
{t("section.viewAll")} <Icon name="arrowRight" />
|
|
73
|
+
</Link>
|
|
74
|
+
)}
|
|
75
|
+
</div>
|
|
76
|
+
<ul className="ub-acc__orders" data-testid="orders-wrapper">
|
|
77
|
+
{orders && orders.length > 0 ? (
|
|
78
|
+
orders.slice(0, 5).map((order) => (
|
|
79
|
+
<li key={order.id} data-testid="order-wrapper" data-value={order.id}>
|
|
80
|
+
<Link href={`/account/orders/details/${order.id}`} className="ub-acc__order" data-testid="open-order-button">
|
|
81
|
+
<span className="ub-acc__ic">
|
|
82
|
+
<Icon name="truck" />
|
|
83
|
+
</span>
|
|
84
|
+
<span>
|
|
85
|
+
<b data-testid="order-id" data-value={order.display_id}>
|
|
86
|
+
#{order.display_id}
|
|
87
|
+
</b>
|
|
88
|
+
<small data-testid="order-created-date">{date.format(new Date(order.created_at))}</small>
|
|
89
|
+
</span>
|
|
90
|
+
<span className="ub-acc__amount" data-testid="order-amount">
|
|
91
|
+
{convertToLocale({ amount: order.total, currency_code: order.currency_code })}
|
|
92
|
+
</span>
|
|
93
|
+
<Icon name="arrowRight" />
|
|
94
|
+
</Link>
|
|
95
|
+
</li>
|
|
96
|
+
))
|
|
97
|
+
) : (
|
|
98
|
+
<li className="ub-acc__empty" data-testid="no-orders-container">
|
|
99
|
+
<span className="ub-acc__ic">
|
|
100
|
+
<Icon name="cart" />
|
|
101
|
+
</span>
|
|
102
|
+
<b>{t("account.noRecentOrders")}</b>
|
|
103
|
+
<Link href="/store" className="ub-acc__shop">
|
|
104
|
+
{t("account.keepShopping")} <Icon name="arrowRight" />
|
|
105
|
+
</Link>
|
|
106
|
+
</li>
|
|
107
|
+
)}
|
|
108
|
+
</ul>
|
|
109
|
+
</section>
|
|
135
110
|
</div>
|
|
136
111
|
)
|
|
137
112
|
}
|
|
138
113
|
|
|
139
114
|
const getProfileCompletion = (customer: HttpTypes.StoreCustomer | null) => {
|
|
115
|
+
if (!customer) return 0
|
|
140
116
|
let count = 0
|
|
141
|
-
|
|
142
|
-
if (
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (customer.email) {
|
|
147
|
-
count++
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (customer.first_name && customer.last_name) {
|
|
151
|
-
count++
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (customer.phone) {
|
|
155
|
-
count++
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const billingAddress = customer.addresses?.find(
|
|
159
|
-
(addr) => addr.is_default_billing
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
if (billingAddress) {
|
|
163
|
-
count++
|
|
164
|
-
}
|
|
165
|
-
|
|
117
|
+
if (customer.email) count++
|
|
118
|
+
if (customer.first_name && customer.last_name) count++
|
|
119
|
+
if (customer.phone) count++
|
|
120
|
+
if (customer.addresses?.find((addr) => addr.is_default_billing)) count++
|
|
166
121
|
return (count / 4) * 100
|
|
167
122
|
}
|
|
168
123
|
|
package/templates/storefront/src/modules/account/components/profile-billing-address/index.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import React, { useEffect, useMemo, useActionState } from "react"
|
|
|
4
4
|
|
|
5
5
|
import { useT } from "@lib/boutique/i18n-client"
|
|
6
6
|
import Input from "@modules/common/components/input"
|
|
7
|
+
import PhoneInput from "@modules/common/components/phone-input"
|
|
7
8
|
import NativeSelect from "@modules/common/components/native-select"
|
|
8
9
|
|
|
9
10
|
import AccountInfo from "../account-info"
|
|
@@ -125,11 +126,9 @@ const ProfileBillingAddress: React.FC<MyInformationProps> = ({
|
|
|
125
126
|
defaultValue={billingAddress?.company || undefined}
|
|
126
127
|
data-testid="billing-company-input"
|
|
127
128
|
/>
|
|
128
|
-
<
|
|
129
|
+
<PhoneInput
|
|
129
130
|
label="form.phone"
|
|
130
131
|
name="phone"
|
|
131
|
-
type="phone"
|
|
132
|
-
autoComplete="phone"
|
|
133
132
|
required
|
|
134
133
|
defaultValue={billingAddress?.phone ?? customer?.phone ?? ""}
|
|
135
134
|
data-testid="billing-phone-input"
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import React, { useEffect, useActionState } from "react";
|
|
4
4
|
|
|
5
5
|
import Input from "@modules/common/components/input"
|
|
6
|
+
import PhoneInput from "@modules/common/components/phone-input"
|
|
6
7
|
|
|
7
8
|
import AccountInfo from "../account-info"
|
|
8
9
|
import { HttpTypes } from "@medusajs/types"
|
|
@@ -56,11 +57,9 @@ const ProfileEmail: React.FC<MyInformationProps> = ({ customer }) => {
|
|
|
56
57
|
data-testid="account-phone-editor"
|
|
57
58
|
>
|
|
58
59
|
<div className="grid grid-cols-1 gap-y-2">
|
|
59
|
-
<
|
|
60
|
+
<PhoneInput
|
|
60
61
|
label="form.phone"
|
|
61
62
|
name="phone"
|
|
62
|
-
type="phone"
|
|
63
|
-
autoComplete="phone"
|
|
64
63
|
required
|
|
65
64
|
defaultValue={customer.phone ?? ""}
|
|
66
65
|
data-testid="phone-input"
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { T } from "@lib/boutique/i18n-client"
|
|
5
5
|
import { useActionState } from "react"
|
|
6
6
|
import Input from "@modules/common/components/input"
|
|
7
|
+
import PhoneInput from "@modules/common/components/phone-input"
|
|
7
8
|
import { LOGIN_VIEW } from "@modules/account/templates/login-template"
|
|
8
9
|
import ErrorMessage from "@modules/checkout/components/error-message"
|
|
9
10
|
import { SubmitButton } from "@modules/checkout/components/submit-button"
|
|
@@ -52,11 +53,9 @@ const Register = ({ setCurrentView }: Props) => {
|
|
|
52
53
|
autoComplete="email"
|
|
53
54
|
data-testid="email-input"
|
|
54
55
|
/>
|
|
55
|
-
<
|
|
56
|
+
<PhoneInput
|
|
56
57
|
label="form.phone"
|
|
57
58
|
name="phone"
|
|
58
|
-
type="tel"
|
|
59
|
-
autoComplete="tel"
|
|
60
59
|
data-testid="phone-input"
|
|
61
60
|
/>
|
|
62
61
|
<Input
|