@doswiftly/cli 0.1.24 → 0.2.1
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/dist/commands/check.js +2 -2
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +8 -5
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts +13 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +155 -63
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +3 -4
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +271 -166
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/sdk.d.ts +1 -1
- package/dist/commands/sdk.js +3 -3
- package/dist/commands/sdk.js.map +1 -1
- package/dist/commands/template.d.ts.map +1 -1
- package/dist/commands/template.js +4 -31
- package/dist/commands/template.js.map +1 -1
- package/dist/commands/verify.js +5 -5
- package/dist/commands/verify.js.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/i18n.d.ts +12 -0
- package/dist/lib/i18n.d.ts.map +1 -1
- package/dist/lib/i18n.js +24 -0
- package/dist/lib/i18n.js.map +1 -1
- package/dist/lib/proxy-server.d.ts +22 -6
- package/dist/lib/proxy-server.d.ts.map +1 -1
- package/dist/lib/proxy-server.js +174 -75
- package/dist/lib/proxy-server.js.map +1 -1
- package/package.json +1 -1
- package/dist/commands/types.d.ts +0 -5
- package/dist/commands/types.d.ts.map +0 -1
- package/dist/commands/types.js +0 -82
- package/dist/commands/types.js.map +0 -1
- package/templates/storefront-minimal/.env.example +0 -10
- package/templates/storefront-minimal/.github/workflows/build-template.yml +0 -119
- package/templates/storefront-minimal/app/globals.css +0 -18
- package/templates/storefront-minimal/app/layout.tsx +0 -26
- package/templates/storefront-minimal/app/page.tsx +0 -93
- package/templates/storefront-minimal/lib/graphql-client.ts +0 -23
- package/templates/storefront-minimal/next.config.ts +0 -15
- package/templates/storefront-minimal/open-next.config.ts +0 -3
- package/templates/storefront-minimal/package.json +0 -30
- package/templates/storefront-minimal/postcss.config.mjs +0 -5
- package/templates/storefront-minimal/tailwind.config.ts +0 -14
- package/templates/storefront-minimal/tsconfig.json +0 -27
- package/templates/storefront-minimal/wrangler.toml +0 -24
- package/templates/storefront-nextjs/.env.example +0 -68
- package/templates/storefront-nextjs/.github/workflows/build-template.yml +0 -119
- package/templates/storefront-nextjs/README.md +0 -524
- package/templates/storefront-nextjs/app/account/orders/page.tsx +0 -216
- package/templates/storefront-nextjs/app/account/page.tsx +0 -167
- package/templates/storefront-nextjs/app/auth/login/page.tsx +0 -135
- package/templates/storefront-nextjs/app/auth/register/page.tsx +0 -212
- package/templates/storefront-nextjs/app/cart/page.tsx +0 -263
- package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +0 -200
- package/templates/storefront-nextjs/app/categories/page.tsx +0 -58
- package/templates/storefront-nextjs/app/checkout/page.tsx +0 -351
- package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +0 -158
- package/templates/storefront-nextjs/app/collections/page.tsx +0 -61
- package/templates/storefront-nextjs/app/globals.css +0 -98
- package/templates/storefront-nextjs/app/layout.tsx +0 -39
- package/templates/storefront-nextjs/app/page.tsx +0 -136
- package/templates/storefront-nextjs/app/products/[slug]/page.tsx +0 -119
- package/templates/storefront-nextjs/app/products/page.tsx +0 -107
- package/templates/storefront-nextjs/app/search/page.tsx +0 -127
- package/templates/storefront-nextjs/components/auth/auth-guard.tsx +0 -94
- package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +0 -77
- package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +0 -29
- package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +0 -217
- package/templates/storefront-nextjs/components/commerce/pagination.tsx +0 -62
- package/templates/storefront-nextjs/components/commerce/product-actions.tsx +0 -135
- package/templates/storefront-nextjs/components/commerce/product-filters.tsx +0 -109
- package/templates/storefront-nextjs/components/commerce/product-price.tsx +0 -375
- package/templates/storefront-nextjs/components/commerce/search-input.tsx +0 -178
- package/templates/storefront-nextjs/components/commerce/sort-select.tsx +0 -64
- package/templates/storefront-nextjs/components/commerce/variant-selector.tsx +0 -210
- package/templates/storefront-nextjs/components/layout/footer.tsx +0 -107
- package/templates/storefront-nextjs/components/layout/header.tsx +0 -104
- package/templates/storefront-nextjs/components/providers.tsx +0 -62
- package/templates/storefront-nextjs/lib/auth/routes.ts +0 -52
- package/templates/storefront-nextjs/lib/currency.tsx +0 -140
- package/templates/storefront-nextjs/lib/format.ts +0 -159
- package/templates/storefront-nextjs/lib/graphql-queries.ts +0 -629
- package/templates/storefront-nextjs/lib/hooks.ts +0 -30
- package/templates/storefront-nextjs/middleware.ts +0 -80
- package/templates/storefront-nextjs/next.config.ts +0 -37
- package/templates/storefront-nextjs/open-next.config.ts +0 -3
- package/templates/storefront-nextjs/package.dev.json +0 -30
- package/templates/storefront-nextjs/package.json +0 -32
- package/templates/storefront-nextjs/package.json.template +0 -32
- package/templates/storefront-nextjs/postcss.config.mjs +0 -8
- package/templates/storefront-nextjs/tailwind.config.ts +0 -111
- package/templates/storefront-nextjs/tsconfig.json +0 -27
- package/templates/storefront-nextjs/wrangler.toml +0 -24
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import Link from "next/link";
|
|
4
|
-
import { useCustomer } from "@doswiftly/storefront-sdk/graphql/client";
|
|
5
|
-
import { useAuth } from "@doswiftly/storefront-sdk/graphql/react";
|
|
6
|
-
import { AuthGuard } from "@/components/auth/auth-guard";
|
|
7
|
-
|
|
8
|
-
function OrdersContent() {
|
|
9
|
-
const { customerToken } = useAuth();
|
|
10
|
-
const { data, isLoading } = useCustomer(
|
|
11
|
-
{ customerAccessToken: customerToken! },
|
|
12
|
-
{ enabled: !!customerToken }
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
if (isLoading) {
|
|
16
|
-
return (
|
|
17
|
-
<div className="container mx-auto px-4 py-8">
|
|
18
|
-
<div className="flex items-center justify-center py-12">
|
|
19
|
-
<div className="h-8 w-8 animate-spin rounded-full border-4 border-gray-200 border-t-gray-900" />
|
|
20
|
-
</div>
|
|
21
|
-
</div>
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const orders = data?.customer?.orders?.edges?.map((edge) => edge.node) ?? [];
|
|
26
|
-
|
|
27
|
-
// Map status to display text and color
|
|
28
|
-
const getFinancialStatusDisplay = (status: string) => {
|
|
29
|
-
const statusMap: Record<string, { text: string; className: string }> = {
|
|
30
|
-
PAID: { text: "Paid", className: "bg-green-100 text-green-800" },
|
|
31
|
-
PENDING: { text: "Pending", className: "bg-yellow-100 text-yellow-800" },
|
|
32
|
-
AUTHORIZED: {
|
|
33
|
-
text: "Authorized",
|
|
34
|
-
className: "bg-blue-100 text-blue-800",
|
|
35
|
-
},
|
|
36
|
-
REFUNDED: { text: "Refunded", className: "bg-gray-100 text-gray-800" },
|
|
37
|
-
PARTIALLY_REFUNDED: {
|
|
38
|
-
text: "Partially Refunded",
|
|
39
|
-
className: "bg-orange-100 text-orange-800",
|
|
40
|
-
},
|
|
41
|
-
VOIDED: { text: "Voided", className: "bg-red-100 text-red-800" },
|
|
42
|
-
};
|
|
43
|
-
return (
|
|
44
|
-
statusMap[status] ?? {
|
|
45
|
-
text: status,
|
|
46
|
-
className: "bg-gray-100 text-gray-800",
|
|
47
|
-
}
|
|
48
|
-
);
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const getFulfillmentStatusDisplay = (status: string) => {
|
|
52
|
-
const statusMap: Record<string, { text: string; className: string }> = {
|
|
53
|
-
FULFILLED: {
|
|
54
|
-
text: "Fulfilled",
|
|
55
|
-
className: "bg-green-100 text-green-800",
|
|
56
|
-
},
|
|
57
|
-
UNFULFILLED: {
|
|
58
|
-
text: "Unfulfilled",
|
|
59
|
-
className: "bg-yellow-100 text-yellow-800",
|
|
60
|
-
},
|
|
61
|
-
PARTIALLY_FULFILLED: {
|
|
62
|
-
text: "Partially Fulfilled",
|
|
63
|
-
className: "bg-blue-100 text-blue-800",
|
|
64
|
-
},
|
|
65
|
-
SCHEDULED: {
|
|
66
|
-
text: "Scheduled",
|
|
67
|
-
className: "bg-purple-100 text-purple-800",
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
return (
|
|
71
|
-
statusMap[status] ?? {
|
|
72
|
-
text: status,
|
|
73
|
-
className: "bg-gray-100 text-gray-800",
|
|
74
|
-
}
|
|
75
|
-
);
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
return (
|
|
79
|
-
<div className="container mx-auto px-4 py-8">
|
|
80
|
-
{/* Breadcrumb */}
|
|
81
|
-
<nav className="mb-4 text-sm">
|
|
82
|
-
<ol className="flex items-center gap-2">
|
|
83
|
-
<li>
|
|
84
|
-
<Link href="/account" className="text-gray-500 hover:text-gray-700">
|
|
85
|
-
Account
|
|
86
|
-
</Link>
|
|
87
|
-
</li>
|
|
88
|
-
<li className="text-gray-400">/</li>
|
|
89
|
-
<li className="text-gray-900">Orders</li>
|
|
90
|
-
</ol>
|
|
91
|
-
</nav>
|
|
92
|
-
|
|
93
|
-
{/* Page Header */}
|
|
94
|
-
<h1 className="mb-8 text-3xl font-bold text-gray-900">Order History</h1>
|
|
95
|
-
|
|
96
|
-
{/* Orders List */}
|
|
97
|
-
{orders.length === 0 ? (
|
|
98
|
-
<div className="rounded-lg border border-gray-200 p-12 text-center">
|
|
99
|
-
<p className="mb-4 text-gray-500">
|
|
100
|
-
You haven't placed any orders yet.
|
|
101
|
-
</p>
|
|
102
|
-
<Link
|
|
103
|
-
href="/products"
|
|
104
|
-
className="inline-block rounded-lg bg-gray-900 px-6 py-3 font-medium text-white hover:bg-gray-800"
|
|
105
|
-
>
|
|
106
|
-
Start Shopping
|
|
107
|
-
</Link>
|
|
108
|
-
</div>
|
|
109
|
-
) : (
|
|
110
|
-
<div className="space-y-4">
|
|
111
|
-
{orders.map((order) => {
|
|
112
|
-
const financialStatus = getFinancialStatusDisplay(
|
|
113
|
-
order.financialStatus
|
|
114
|
-
);
|
|
115
|
-
const fulfillmentStatus = getFulfillmentStatusDisplay(
|
|
116
|
-
order.fulfillmentStatus
|
|
117
|
-
);
|
|
118
|
-
const date = new Date(order.processedAt);
|
|
119
|
-
|
|
120
|
-
return (
|
|
121
|
-
<div
|
|
122
|
-
key={order.id}
|
|
123
|
-
className="rounded-lg border border-gray-200 p-6"
|
|
124
|
-
>
|
|
125
|
-
{/* Order Header */}
|
|
126
|
-
<div className="mb-4 flex flex-wrap items-start justify-between gap-4">
|
|
127
|
-
<div>
|
|
128
|
-
<p className="text-lg font-semibold text-gray-900">
|
|
129
|
-
Order #{order.orderNumber}
|
|
130
|
-
</p>
|
|
131
|
-
<p className="text-sm text-gray-500">
|
|
132
|
-
{date.toLocaleDateString("en-US", {
|
|
133
|
-
year: "numeric",
|
|
134
|
-
month: "long",
|
|
135
|
-
day: "numeric",
|
|
136
|
-
})}
|
|
137
|
-
</p>
|
|
138
|
-
</div>
|
|
139
|
-
<div className="flex flex-wrap gap-2">
|
|
140
|
-
<span
|
|
141
|
-
className={`rounded-full px-3 py-1 text-xs font-medium ${financialStatus.className}`}
|
|
142
|
-
>
|
|
143
|
-
{financialStatus.text}
|
|
144
|
-
</span>
|
|
145
|
-
<span
|
|
146
|
-
className={`rounded-full px-3 py-1 text-xs font-medium ${fulfillmentStatus.className}`}
|
|
147
|
-
>
|
|
148
|
-
{fulfillmentStatus.text}
|
|
149
|
-
</span>
|
|
150
|
-
</div>
|
|
151
|
-
</div>
|
|
152
|
-
|
|
153
|
-
{/* Order Details */}
|
|
154
|
-
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
155
|
-
<div>
|
|
156
|
-
<span className="text-sm text-gray-500">Items</span>
|
|
157
|
-
<p className="font-medium text-gray-900">
|
|
158
|
-
{order.lineItemsCount}{" "}
|
|
159
|
-
{order.lineItemsCount === 1 ? "item" : "items"}
|
|
160
|
-
</p>
|
|
161
|
-
</div>
|
|
162
|
-
<div>
|
|
163
|
-
<span className="text-sm text-gray-500">Subtotal</span>
|
|
164
|
-
<p className="font-medium text-gray-900">
|
|
165
|
-
{order.subtotalPrice.currencyCode}{" "}
|
|
166
|
-
{order.subtotalPrice.amount}
|
|
167
|
-
</p>
|
|
168
|
-
</div>
|
|
169
|
-
{order.totalShipping && (
|
|
170
|
-
<div>
|
|
171
|
-
<span className="text-sm text-gray-500">Shipping</span>
|
|
172
|
-
<p className="font-medium text-gray-900">
|
|
173
|
-
{order.totalShipping.currencyCode}{" "}
|
|
174
|
-
{order.totalShipping.amount}
|
|
175
|
-
</p>
|
|
176
|
-
</div>
|
|
177
|
-
)}
|
|
178
|
-
<div>
|
|
179
|
-
<span className="text-sm text-gray-500">Total</span>
|
|
180
|
-
<p className="font-medium text-gray-900">
|
|
181
|
-
{order.totalPrice.currencyCode} {order.totalPrice.amount}
|
|
182
|
-
</p>
|
|
183
|
-
</div>
|
|
184
|
-
</div>
|
|
185
|
-
|
|
186
|
-
{/* Shipping Address */}
|
|
187
|
-
{order.shippingAddress && (
|
|
188
|
-
<div className="mt-4 border-t border-gray-200 pt-4">
|
|
189
|
-
<span className="text-sm text-gray-500">Ship to</span>
|
|
190
|
-
<p className="text-sm text-gray-900">
|
|
191
|
-
{order.shippingAddress.firstName}{" "}
|
|
192
|
-
{order.shippingAddress.lastName},{" "}
|
|
193
|
-
{order.shippingAddress.address1},{" "}
|
|
194
|
-
{order.shippingAddress.city},{" "}
|
|
195
|
-
{order.shippingAddress.province}{" "}
|
|
196
|
-
{order.shippingAddress.zip},{" "}
|
|
197
|
-
{order.shippingAddress.country}
|
|
198
|
-
</p>
|
|
199
|
-
</div>
|
|
200
|
-
)}
|
|
201
|
-
</div>
|
|
202
|
-
);
|
|
203
|
-
})}
|
|
204
|
-
</div>
|
|
205
|
-
)}
|
|
206
|
-
</div>
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export default function OrdersPage() {
|
|
211
|
-
return (
|
|
212
|
-
<AuthGuard>
|
|
213
|
-
<OrdersContent />
|
|
214
|
-
</AuthGuard>
|
|
215
|
-
);
|
|
216
|
-
}
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import Link from "next/link";
|
|
4
|
-
import { useRouter } from "next/navigation";
|
|
5
|
-
import { useAuth, useLogout } from "@doswiftly/storefront-sdk/graphql/react";
|
|
6
|
-
import { useCustomer } from "@doswiftly/storefront-sdk/graphql/client";
|
|
7
|
-
import { AuthGuard } from "@/components/auth/auth-guard";
|
|
8
|
-
|
|
9
|
-
function AccountContent() {
|
|
10
|
-
const router = useRouter();
|
|
11
|
-
const { customerToken } = useAuth();
|
|
12
|
-
const { logout } = useLogout();
|
|
13
|
-
const { data, isLoading } = useCustomer(
|
|
14
|
-
{ customerAccessToken: customerToken! },
|
|
15
|
-
{ enabled: !!customerToken }
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
const handleLogout = () => {
|
|
19
|
-
logout();
|
|
20
|
-
router.push("/");
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
if (isLoading) {
|
|
24
|
-
return (
|
|
25
|
-
<div className="container mx-auto px-4 py-8">
|
|
26
|
-
<div className="flex items-center justify-center py-12">
|
|
27
|
-
<div className="h-8 w-8 animate-spin rounded-full border-4 border-gray-200 border-t-gray-900" />
|
|
28
|
-
</div>
|
|
29
|
-
</div>
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const customer = data?.customer;
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<div className="container mx-auto px-4 py-8">
|
|
37
|
-
{/* Page Header */}
|
|
38
|
-
<div className="mb-8 flex items-center justify-between">
|
|
39
|
-
<h1 className="text-3xl font-bold text-gray-900">My Account</h1>
|
|
40
|
-
<button
|
|
41
|
-
onClick={handleLogout}
|
|
42
|
-
className="rounded-lg border border-gray-300 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50"
|
|
43
|
-
>
|
|
44
|
-
Logout
|
|
45
|
-
</button>
|
|
46
|
-
</div>
|
|
47
|
-
|
|
48
|
-
{/* Account Grid */}
|
|
49
|
-
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
|
50
|
-
{/* Profile Card */}
|
|
51
|
-
<div className="rounded-lg border border-gray-200 p-6">
|
|
52
|
-
<h2 className="mb-4 text-lg font-semibold text-gray-900">Profile</h2>
|
|
53
|
-
<div className="space-y-3">
|
|
54
|
-
<div>
|
|
55
|
-
<span className="text-sm text-gray-500">Name</span>
|
|
56
|
-
<p className="font-medium text-gray-900">
|
|
57
|
-
{customer?.firstName && customer?.lastName
|
|
58
|
-
? `${customer.firstName} ${customer.lastName}`
|
|
59
|
-
: "Not set"}
|
|
60
|
-
</p>
|
|
61
|
-
</div>
|
|
62
|
-
<div>
|
|
63
|
-
<span className="text-sm text-gray-500">Email</span>
|
|
64
|
-
<p className="font-medium text-gray-900">{customer?.email}</p>
|
|
65
|
-
</div>
|
|
66
|
-
{customer?.phone && (
|
|
67
|
-
<div>
|
|
68
|
-
<span className="text-sm text-gray-500">Phone</span>
|
|
69
|
-
<p className="font-medium text-gray-900">{customer.phone}</p>
|
|
70
|
-
</div>
|
|
71
|
-
)}
|
|
72
|
-
</div>
|
|
73
|
-
</div>
|
|
74
|
-
|
|
75
|
-
{/* Orders Card */}
|
|
76
|
-
<Link
|
|
77
|
-
href="/account/orders"
|
|
78
|
-
className="rounded-lg border border-gray-200 p-6 transition hover:border-gray-300 hover:shadow-sm"
|
|
79
|
-
>
|
|
80
|
-
<h2 className="mb-2 text-lg font-semibold text-gray-900">Orders</h2>
|
|
81
|
-
<p className="text-sm text-gray-600">
|
|
82
|
-
View your order history and track shipments
|
|
83
|
-
</p>
|
|
84
|
-
<div className="mt-4 flex items-center text-sm font-medium text-gray-900">
|
|
85
|
-
View orders
|
|
86
|
-
<svg
|
|
87
|
-
className="ml-2 h-4 w-4"
|
|
88
|
-
fill="none"
|
|
89
|
-
viewBox="0 0 24 24"
|
|
90
|
-
stroke="currentColor"
|
|
91
|
-
>
|
|
92
|
-
<path
|
|
93
|
-
strokeLinecap="round"
|
|
94
|
-
strokeLinejoin="round"
|
|
95
|
-
strokeWidth={2}
|
|
96
|
-
d="M9 5l7 7-7 7"
|
|
97
|
-
/>
|
|
98
|
-
</svg>
|
|
99
|
-
</div>
|
|
100
|
-
</Link>
|
|
101
|
-
|
|
102
|
-
{/* Addresses Card */}
|
|
103
|
-
<Link
|
|
104
|
-
href="/account/addresses"
|
|
105
|
-
className="rounded-lg border border-gray-200 p-6 transition hover:border-gray-300 hover:shadow-sm"
|
|
106
|
-
>
|
|
107
|
-
<h2 className="mb-2 text-lg font-semibold text-gray-900">
|
|
108
|
-
Addresses
|
|
109
|
-
</h2>
|
|
110
|
-
<p className="text-sm text-gray-600">
|
|
111
|
-
Manage your shipping and billing addresses
|
|
112
|
-
</p>
|
|
113
|
-
<div className="mt-4 flex items-center text-sm font-medium text-gray-900">
|
|
114
|
-
Manage addresses
|
|
115
|
-
<svg
|
|
116
|
-
className="ml-2 h-4 w-4"
|
|
117
|
-
fill="none"
|
|
118
|
-
viewBox="0 0 24 24"
|
|
119
|
-
stroke="currentColor"
|
|
120
|
-
>
|
|
121
|
-
<path
|
|
122
|
-
strokeLinecap="round"
|
|
123
|
-
strokeLinejoin="round"
|
|
124
|
-
strokeWidth={2}
|
|
125
|
-
d="M9 5l7 7-7 7"
|
|
126
|
-
/>
|
|
127
|
-
</svg>
|
|
128
|
-
</div>
|
|
129
|
-
</Link>
|
|
130
|
-
</div>
|
|
131
|
-
|
|
132
|
-
{/* Default Addresses */}
|
|
133
|
-
{customer?.defaultAddress && (
|
|
134
|
-
<div className="mt-8">
|
|
135
|
-
<h2 className="mb-4 text-lg font-semibold text-gray-900">
|
|
136
|
-
Default Address
|
|
137
|
-
</h2>
|
|
138
|
-
<div className="rounded-lg border border-gray-200 p-4">
|
|
139
|
-
<p className="text-gray-900">
|
|
140
|
-
{customer.defaultAddress.firstName}{" "}
|
|
141
|
-
{customer.defaultAddress.lastName}
|
|
142
|
-
</p>
|
|
143
|
-
<p className="text-gray-600">{customer.defaultAddress.address1}</p>
|
|
144
|
-
{customer.defaultAddress.address2 && (
|
|
145
|
-
<p className="text-gray-600">
|
|
146
|
-
{customer.defaultAddress.address2}
|
|
147
|
-
</p>
|
|
148
|
-
)}
|
|
149
|
-
<p className="text-gray-600">
|
|
150
|
-
{customer.defaultAddress.city}, {customer.defaultAddress.province}{" "}
|
|
151
|
-
{customer.defaultAddress.zip}
|
|
152
|
-
</p>
|
|
153
|
-
<p className="text-gray-600">{customer.defaultAddress.country}</p>
|
|
154
|
-
</div>
|
|
155
|
-
</div>
|
|
156
|
-
)}
|
|
157
|
-
</div>
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export default function AccountPage() {
|
|
162
|
-
return (
|
|
163
|
-
<AuthGuard>
|
|
164
|
-
<AccountContent />
|
|
165
|
-
</AuthGuard>
|
|
166
|
-
);
|
|
167
|
-
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useState, FormEvent, Suspense } from "react";
|
|
4
|
-
import Link from "next/link";
|
|
5
|
-
import { useRouter, useSearchParams } from "next/navigation";
|
|
6
|
-
import { useLogin } from "@doswiftly/storefront-sdk/graphql/react";
|
|
7
|
-
import { AuthGuard } from "@/components/auth/auth-guard";
|
|
8
|
-
|
|
9
|
-
function LoginFormContent() {
|
|
10
|
-
const router = useRouter();
|
|
11
|
-
const searchParams = useSearchParams();
|
|
12
|
-
const login = useLogin();
|
|
13
|
-
|
|
14
|
-
const [email, setEmail] = useState("");
|
|
15
|
-
const [password, setPassword] = useState("");
|
|
16
|
-
const [error, setError] = useState<string | null>(null);
|
|
17
|
-
|
|
18
|
-
const handleSubmit = async (e: FormEvent) => {
|
|
19
|
-
e.preventDefault();
|
|
20
|
-
setError(null);
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
const result = await login.mutateAsync({
|
|
24
|
-
input: { email, password },
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// Check for user errors
|
|
28
|
-
const userErrors = result.customerAccessTokenCreate?.userErrors;
|
|
29
|
-
if (userErrors && userErrors.length > 0) {
|
|
30
|
-
setError(userErrors[0].message);
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Success - redirect to original page or account
|
|
35
|
-
const redirectTo = searchParams.get("redirect") || "/account";
|
|
36
|
-
router.push(redirectTo);
|
|
37
|
-
} catch (err) {
|
|
38
|
-
setError("Login failed. Please try again.");
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<div className="container mx-auto flex min-h-[60vh] items-center justify-center px-4">
|
|
44
|
-
<div className="w-full max-w-md">
|
|
45
|
-
<h1 className="mb-8 text-center text-3xl font-bold text-gray-900">
|
|
46
|
-
Login
|
|
47
|
-
</h1>
|
|
48
|
-
|
|
49
|
-
{error && (
|
|
50
|
-
<div className="mb-6 rounded-lg bg-red-50 p-4 text-red-700">
|
|
51
|
-
{error}
|
|
52
|
-
</div>
|
|
53
|
-
)}
|
|
54
|
-
|
|
55
|
-
<form onSubmit={handleSubmit} className="space-y-6">
|
|
56
|
-
<div>
|
|
57
|
-
<label
|
|
58
|
-
htmlFor="email"
|
|
59
|
-
className="mb-2 block text-sm font-medium text-gray-900"
|
|
60
|
-
>
|
|
61
|
-
Email
|
|
62
|
-
</label>
|
|
63
|
-
<input
|
|
64
|
-
type="email"
|
|
65
|
-
id="email"
|
|
66
|
-
value={email}
|
|
67
|
-
onChange={(e) => setEmail(e.target.value)}
|
|
68
|
-
required
|
|
69
|
-
className="w-full rounded-lg border border-gray-300 px-4 py-3 focus:border-gray-900 focus:outline-none"
|
|
70
|
-
placeholder="your@email.com"
|
|
71
|
-
/>
|
|
72
|
-
</div>
|
|
73
|
-
|
|
74
|
-
<div>
|
|
75
|
-
<label
|
|
76
|
-
htmlFor="password"
|
|
77
|
-
className="mb-2 block text-sm font-medium text-gray-900"
|
|
78
|
-
>
|
|
79
|
-
Password
|
|
80
|
-
</label>
|
|
81
|
-
<input
|
|
82
|
-
type="password"
|
|
83
|
-
id="password"
|
|
84
|
-
value={password}
|
|
85
|
-
onChange={(e) => setPassword(e.target.value)}
|
|
86
|
-
required
|
|
87
|
-
className="w-full rounded-lg border border-gray-300 px-4 py-3 focus:border-gray-900 focus:outline-none"
|
|
88
|
-
placeholder="••••••••"
|
|
89
|
-
/>
|
|
90
|
-
</div>
|
|
91
|
-
|
|
92
|
-
<button
|
|
93
|
-
type="submit"
|
|
94
|
-
disabled={login.isPending}
|
|
95
|
-
className="w-full rounded-lg bg-gray-900 py-3 font-medium text-white transition hover:bg-gray-800 disabled:cursor-not-allowed disabled:opacity-50"
|
|
96
|
-
>
|
|
97
|
-
{login.isPending ? "Logging in..." : "Login"}
|
|
98
|
-
</button>
|
|
99
|
-
</form>
|
|
100
|
-
|
|
101
|
-
<p className="mt-6 text-center text-sm text-gray-600">
|
|
102
|
-
Don't have an account?{" "}
|
|
103
|
-
<Link
|
|
104
|
-
href="/auth/register"
|
|
105
|
-
className="font-medium text-gray-900 hover:underline"
|
|
106
|
-
>
|
|
107
|
-
Register
|
|
108
|
-
</Link>
|
|
109
|
-
</p>
|
|
110
|
-
</div>
|
|
111
|
-
</div>
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function LoginForm() {
|
|
116
|
-
return (
|
|
117
|
-
<Suspense
|
|
118
|
-
fallback={
|
|
119
|
-
<div className="container mx-auto flex min-h-[60vh] items-center justify-center px-4">
|
|
120
|
-
<div className="h-8 w-8 animate-spin rounded-full border-4 border-gray-200 border-t-gray-900" />
|
|
121
|
-
</div>
|
|
122
|
-
}
|
|
123
|
-
>
|
|
124
|
-
<LoginFormContent />
|
|
125
|
-
</Suspense>
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export default function LoginPage() {
|
|
130
|
-
return (
|
|
131
|
-
<AuthGuard requireGuest>
|
|
132
|
-
<LoginForm />
|
|
133
|
-
</AuthGuard>
|
|
134
|
-
);
|
|
135
|
-
}
|