@doswiftly/cli 0.1.17 → 0.1.19
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/README.md +23 -323
- package/dist/commands/check.js +1 -1
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +43 -20
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +4 -4
- package/dist/commands/sdk.js +5 -5
- package/dist/commands/sdk.js.map +1 -1
- package/dist/commands/template.js +4 -4
- package/dist/commands/template.js.map +1 -1
- package/dist/commands/types.js +5 -5
- package/dist/commands/types.js.map +1 -1
- package/dist/commands/verify.js +2 -2
- package/dist/commands/verify.js.map +1 -1
- package/dist/lib/package-manager.d.ts +1 -1
- package/dist/lib/package-manager.js +1 -1
- package/package.json +1 -1
- package/templates/storefront-minimal/wrangler.toml +4 -0
- package/templates/storefront-nextjs/README.md +16 -12
- package/templates/storefront-nextjs/app/account/orders/page.tsx +2 -2
- package/templates/storefront-nextjs/app/account/page.tsx +2 -2
- package/templates/storefront-nextjs/app/auth/login/page.tsx +1 -1
- package/templates/storefront-nextjs/app/auth/register/page.tsx +1 -1
- package/templates/storefront-nextjs/app/cart/page.tsx +1 -1
- package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +2 -2
- package/templates/storefront-nextjs/app/categories/page.tsx +1 -1
- package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +1 -1
- package/templates/storefront-nextjs/app/collections/page.tsx +1 -1
- package/templates/storefront-nextjs/app/page.tsx +1 -1
- package/templates/storefront-nextjs/app/products/[slug]/page.tsx +1 -1
- package/templates/storefront-nextjs/app/products/page.tsx +2 -2
- package/templates/storefront-nextjs/app/search/page.tsx +1 -1
- package/templates/storefront-nextjs/components/auth/auth-guard.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +2 -2
- package/templates/storefront-nextjs/components/commerce/product-filters.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/product-price.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/search-input.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/sort-select.tsx +1 -1
- package/templates/storefront-nextjs/components/providers.tsx +1 -1
- package/templates/storefront-nextjs/lib/currency.tsx +3 -3
- package/templates/storefront-nextjs/lib/format.ts +1 -1
- package/templates/storefront-nextjs/lib/graphql-queries.ts +3 -3
- package/templates/storefront-nextjs/package.dev.json +1 -1
- package/templates/storefront-nextjs/package.json +1 -1
- package/templates/storefront-nextjs/package.json.template +1 -1
- package/templates/storefront-nextjs/wrangler.toml +4 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +47 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +47 -0
- package/templates/storefront-nextjs-shadcn/CLAUDE.md +148 -35
- package/templates/storefront-nextjs-shadcn/README.md +29 -162
- package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +98 -91
- package/templates/storefront-nextjs-shadcn/app/account/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/account/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/account/loyalty/page.tsx +53 -162
- package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/loading.tsx +60 -0
- package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +36 -47
- package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +46 -29
- package/templates/storefront-nextjs-shadcn/app/account/page.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +108 -71
- package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +2 -86
- package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +2 -124
- package/templates/storefront-nextjs-shadcn/app/auth/forgot-password/page.tsx +10 -5
- package/templates/storefront-nextjs-shadcn/app/blog/[slug]/loading.tsx +17 -0
- package/templates/storefront-nextjs-shadcn/app/blog/[slug]/page.tsx +43 -2
- package/templates/storefront-nextjs-shadcn/app/blog/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/brands/page.tsx +2 -1
- package/templates/storefront-nextjs-shadcn/app/cart/loading.tsx +26 -0
- package/templates/storefront-nextjs-shadcn/app/cart/page.tsx +6 -3
- package/templates/storefront-nextjs-shadcn/app/categories/[slug]/category-products-client.tsx +56 -0
- package/templates/storefront-nextjs-shadcn/app/categories/[slug]/loading.tsx +32 -0
- package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +76 -59
- package/templates/storefront-nextjs-shadcn/app/categories/page.tsx +8 -4
- package/templates/storefront-nextjs-shadcn/app/checkout/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/checkout/loading.tsx +31 -0
- package/templates/storefront-nextjs-shadcn/app/checkout/page.tsx +116 -79
- package/templates/storefront-nextjs-shadcn/app/collections/[handle]/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/collections/[handle]/page.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/app/collections/loading.tsx +18 -0
- package/templates/storefront-nextjs-shadcn/app/collections/page.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/app/global-error.tsx +117 -0
- package/templates/storefront-nextjs-shadcn/app/globals.css +8 -0
- package/templates/storefront-nextjs-shadcn/app/layout.tsx +46 -11
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/loading.tsx +29 -0
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/page.tsx +6 -6
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/product-client.tsx +15 -61
- package/templates/storefront-nextjs-shadcn/app/products/loading.tsx +32 -0
- package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +405 -151
- package/templates/storefront-nextjs-shadcn/app/search/loading.tsx +18 -0
- package/templates/storefront-nextjs-shadcn/app/wishlist/page.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/codegen.ts +48 -31
- package/templates/storefront-nextjs-shadcn/components/account/customer-info.fragment.graphql +36 -0
- package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +3 -1
- package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +26 -24
- package/templates/storefront-nextjs-shadcn/components/account/order-summary.fragment.graphql +36 -0
- package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +9 -9
- package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +11 -37
- package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +37 -23
- package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +4 -3
- package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/cart/cart-line.fragment.graphql +53 -0
- package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +22 -7
- package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +35 -11
- package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +3 -3
- package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +5 -5
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +2 -1
- package/templates/storefront-nextjs-shadcn/components/home/collection-card.fragment.graphql +21 -0
- package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +2 -12
- package/templates/storefront-nextjs-shadcn/components/home/index.ts +0 -1
- package/templates/storefront-nextjs-shadcn/components/hydrated.tsx +24 -0
- package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +4 -4
- package/templates/storefront-nextjs-shadcn/components/layout/category-node.fragment.graphql +22 -0
- package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +33 -23
- package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +2 -11
- package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +8 -25
- package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +10 -19
- package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +17 -41
- package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +2 -29
- package/templates/storefront-nextjs-shadcn/components/order/index.ts +6 -1
- package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +3 -1
- package/templates/storefront-nextjs-shadcn/components/product/filter-active-pills.tsx +69 -0
- package/templates/storefront-nextjs-shadcn/components/product/filter-mobile-sheet.tsx +84 -0
- package/templates/storefront-nextjs-shadcn/components/product/filter-price-range.tsx +138 -0
- package/templates/storefront-nextjs-shadcn/components/product/index.ts +9 -2
- package/templates/storefront-nextjs-shadcn/components/product/product-card.fragment.graphql +49 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +3 -31
- package/templates/storefront-nextjs-shadcn/components/product/product-detail.fragment.graphql +52 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +176 -123
- package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +3 -5
- package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +5 -4
- package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +19 -7
- package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +8 -23
- package/templates/storefront-nextjs-shadcn/components/product/product-variant.fragment.graphql +51 -0
- package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +1 -7
- package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +17 -2
- package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +3 -2
- package/templates/storefront-nextjs-shadcn/components/providers/index.ts +1 -1
- package/templates/storefront-nextjs-shadcn/components/providers/stores-provider.tsx +30 -0
- package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/returns/index.ts +2 -2
- package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +3 -2
- package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +3 -2
- package/templates/storefront-nextjs-shadcn/components/ui/form.tsx +174 -0
- package/templates/storefront-nextjs-shadcn/components/ui/index.ts +30 -2
- package/templates/storefront-nextjs-shadcn/components/ui/progress.tsx +40 -0
- package/templates/storefront-nextjs-shadcn/components/ui/sheet.tsx +107 -0
- package/templates/storefront-nextjs-shadcn/components/ui/slider.tsx +33 -0
- package/templates/storefront-nextjs-shadcn/components/ui/textarea.tsx +24 -0
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +3 -1
- package/templates/storefront-nextjs-shadcn/generated/graphql.ts +12779 -0
- package/templates/storefront-nextjs-shadcn/graphql/custom.example.graphql +159 -0
- package/templates/storefront-nextjs-shadcn/hooks/index.ts +2 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-auth-sync.ts +42 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +17 -295
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +51 -19
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +13 -9
- package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +4 -17
- package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +22 -99
- package/templates/storefront-nextjs-shadcn/lib/graphql/config.ts +32 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/fragments.ts +34 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +687 -632
- package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +86 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +131 -182
- package/templates/storefront-nextjs-shadcn/lib/graphql/types.ts +62 -0
- package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +0 -17
- package/templates/storefront-nextjs-shadcn/next-env.d.ts +6 -0
- package/templates/storefront-nextjs-shadcn/package.dev.json +1 -3
- package/templates/storefront-nextjs-shadcn/package.json +12 -13
- package/templates/storefront-nextjs-shadcn/package.json.template +6 -7
- package/templates/storefront-nextjs-shadcn/proxy.ts +3 -4
- package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +41 -39
- package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +64 -75
- package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +178 -177
- package/templates/storefront-nextjs-shadcn/tsconfig.json +23 -5
- package/templates/storefront-nextjs-shadcn/wrangler.toml +4 -0
- package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +0 -282
- package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +0 -190
- package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +0 -263
- package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +0 -135
- package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +0 -142
- package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +0 -448
- package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +0 -307
- package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +0 -245
- package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +0 -103
- package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +0 -168
- package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +0 -160
- package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +0 -220
- package/templates/storefront-nextjs-shadcn/lib/config.ts +0 -46
- package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +0 -254
- package/templates/storefront-nextjs-shadcn/lib/currency/README.md +0 -464
- package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +0 -328
- package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +0 -295
- package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +0 -27
- package/templates/storefront-nextjs-shadcn/lib/format.ts +0 -226
- package/templates/storefront-nextjs-shadcn/lib/hooks.ts +0 -30
- package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +0 -66
- package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +0 -103
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
2
|
+
|
|
3
|
+
export default function OrderDetailLoading() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="container mx-auto px-4 py-8">
|
|
6
|
+
{/* Breadcrumbs */}
|
|
7
|
+
<Skeleton className="mb-6 h-5 w-64" />
|
|
8
|
+
|
|
9
|
+
{/* Back button */}
|
|
10
|
+
<Skeleton className="mb-6 h-10 w-40" />
|
|
11
|
+
|
|
12
|
+
{/* Order header card */}
|
|
13
|
+
<div className="mb-6 rounded-lg border p-6">
|
|
14
|
+
<div className="flex items-center justify-between">
|
|
15
|
+
<div className="space-y-2">
|
|
16
|
+
<Skeleton className="h-7 w-48" />
|
|
17
|
+
<Skeleton className="h-4 w-32" />
|
|
18
|
+
</div>
|
|
19
|
+
<Skeleton className="h-8 w-24 rounded-full" />
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
{/* Order items card */}
|
|
24
|
+
<div className="mb-6 rounded-lg border p-6">
|
|
25
|
+
<Skeleton className="mb-4 h-6 w-24" />
|
|
26
|
+
<div className="space-y-4">
|
|
27
|
+
{[...Array(3)].map((_, i) => (
|
|
28
|
+
<div key={i} className="flex items-center gap-4">
|
|
29
|
+
<Skeleton className="h-16 w-16 rounded-md" />
|
|
30
|
+
<div className="flex-1 space-y-2">
|
|
31
|
+
<Skeleton className="h-4 w-3/4" />
|
|
32
|
+
<Skeleton className="h-4 w-1/4" />
|
|
33
|
+
</div>
|
|
34
|
+
<Skeleton className="h-5 w-20" />
|
|
35
|
+
</div>
|
|
36
|
+
))}
|
|
37
|
+
</div>
|
|
38
|
+
<div className="mt-4 border-t pt-4 space-y-2">
|
|
39
|
+
<Skeleton className="ml-auto h-4 w-32" />
|
|
40
|
+
<Skeleton className="ml-auto h-4 w-32" />
|
|
41
|
+
<Skeleton className="ml-auto h-5 w-36" />
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
{/* Address cards */}
|
|
46
|
+
<div className="grid gap-6 md:grid-cols-2">
|
|
47
|
+
{[...Array(2)].map((_, i) => (
|
|
48
|
+
<div key={i} className="rounded-lg border p-6">
|
|
49
|
+
<Skeleton className="mb-3 h-5 w-36" />
|
|
50
|
+
<div className="space-y-2">
|
|
51
|
+
<Skeleton className="h-4 w-48" />
|
|
52
|
+
<Skeleton className="h-4 w-40" />
|
|
53
|
+
<Skeleton className="h-4 w-32" />
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
))}
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
import { useParams } from "next/navigation";
|
|
4
4
|
import Link from "next/link";
|
|
5
5
|
import { ChevronLeft } from "lucide-react";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { useAuthStore } from "@/stores/auth-store";
|
|
9
|
-
import { CustomerDocument } from "@/generated/graphql";
|
|
6
|
+
import { useCustomerOrder } from "@/lib/graphql/hooks";
|
|
7
|
+
import { useHydrated } from "@doswiftly/storefront-sdk/react";
|
|
10
8
|
import { Button } from "@/components/ui/button";
|
|
11
9
|
import { Breadcrumbs } from "@/components/layout/breadcrumbs";
|
|
12
10
|
import {
|
|
@@ -17,25 +15,13 @@ import {
|
|
|
17
15
|
export default function OrderDetailPage() {
|
|
18
16
|
const params = useParams();
|
|
19
17
|
const orderId = params.id as string;
|
|
20
|
-
const
|
|
21
|
-
const client = getGraphQLClient();
|
|
18
|
+
const hydrated = useHydrated();
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
const { data: customerData, isLoading } = useQuery({
|
|
25
|
-
queryKey: ["customer", "orders", accessToken],
|
|
26
|
-
queryFn: async () => {
|
|
27
|
-
if (!accessToken) return null;
|
|
28
|
-
return client.request(CustomerDocument, { customerAccessToken: accessToken });
|
|
29
|
-
},
|
|
30
|
-
enabled: !!accessToken,
|
|
31
|
-
});
|
|
20
|
+
const { data, isPending, error } = useCustomerOrder(orderId);
|
|
32
21
|
|
|
33
|
-
|
|
34
|
-
const order = customerData?.customer?.orders?.edges?.find(
|
|
35
|
-
(edge) => edge.node.id === orderId
|
|
36
|
-
)?.node;
|
|
22
|
+
const order = data?.customerOrder;
|
|
37
23
|
|
|
38
|
-
if (
|
|
24
|
+
if (!hydrated || isPending) {
|
|
39
25
|
return (
|
|
40
26
|
<div className="container mx-auto px-4 py-8">
|
|
41
27
|
<div className="animate-pulse space-y-4">
|
|
@@ -46,6 +32,20 @@ export default function OrderDetailPage() {
|
|
|
46
32
|
);
|
|
47
33
|
}
|
|
48
34
|
|
|
35
|
+
if (error) {
|
|
36
|
+
return (
|
|
37
|
+
<div className="container mx-auto px-4 py-8">
|
|
38
|
+
<div className="text-center">
|
|
39
|
+
<h1 className="text-2xl font-bold text-destructive">Failed to load order</h1>
|
|
40
|
+
<p className="mt-2 text-muted-foreground">Something went wrong. Please try again later.</p>
|
|
41
|
+
<Link href="/account/orders">
|
|
42
|
+
<Button className="mt-4">Back to Orders</Button>
|
|
43
|
+
</Link>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
49
|
if (!order) {
|
|
50
50
|
return (
|
|
51
51
|
<div className="container mx-auto px-4 py-8">
|
|
@@ -59,23 +59,25 @@ export default function OrderDetailPage() {
|
|
|
59
59
|
);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
const mapFulfillmentStatus = (status?: string | null): OrderDetailsData["status"] => {
|
|
63
|
+
switch (status) {
|
|
64
|
+
case "DELIVERED": return "delivered";
|
|
65
|
+
case "IN_TRANSIT":
|
|
66
|
+
case "FULFILLED": return "shipped";
|
|
67
|
+
case "UNFULFILLED":
|
|
68
|
+
case "PARTIALLY_FULFILLED": return "processing";
|
|
69
|
+
default: return "processing";
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
63
73
|
const orderDetails: OrderDetailsData = {
|
|
64
74
|
id: order.id,
|
|
65
75
|
orderNumber: order.orderNumber?.toString() || order.id,
|
|
66
76
|
date: new Date(order.processedAt).toLocaleDateString(),
|
|
67
|
-
status: order.fulfillmentStatus
|
|
68
|
-
items:
|
|
69
|
-
id: edge.node.variant?.id || edge.node.title,
|
|
70
|
-
title: edge.node.title,
|
|
71
|
-
variantTitle: edge.node.variant?.title || "",
|
|
72
|
-
quantity: edge.node.quantity,
|
|
73
|
-
price: edge.node.originalTotalPrice.amount,
|
|
74
|
-
currency: edge.node.originalTotalPrice.currencyCode,
|
|
75
|
-
imageUrl: edge.node.variant?.image?.url || "",
|
|
76
|
-
})),
|
|
77
|
+
status: mapFulfillmentStatus(order.fulfillmentStatus),
|
|
78
|
+
items: [],
|
|
77
79
|
subtotal: order.subtotalPrice?.amount || "0",
|
|
78
|
-
shipping: order.
|
|
80
|
+
shipping: order.totalShipping?.amount || "0",
|
|
79
81
|
tax: order.totalTax?.amount || "0",
|
|
80
82
|
total: order.totalPrice.amount,
|
|
81
83
|
currency: order.totalPrice.currencyCode,
|
|
@@ -92,21 +94,8 @@ export default function OrderDetailPage() {
|
|
|
92
94
|
phone: order.shippingAddress.phone || "",
|
|
93
95
|
}
|
|
94
96
|
: undefined,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
firstName: order.billingAddress.firstName || "",
|
|
98
|
-
lastName: order.billingAddress.lastName || "",
|
|
99
|
-
address1: order.billingAddress.address1 || "",
|
|
100
|
-
address2: order.billingAddress.address2 || "",
|
|
101
|
-
city: order.billingAddress.city || "",
|
|
102
|
-
province: order.billingAddress.province || "",
|
|
103
|
-
zip: order.billingAddress.zip || "",
|
|
104
|
-
country: order.billingAddress.country || "",
|
|
105
|
-
phone: order.billingAddress.phone || "",
|
|
106
|
-
}
|
|
107
|
-
: undefined,
|
|
108
|
-
trackingNumber: order.successfulFulfillments?.[0]?.trackingInfo?.[0]?.number,
|
|
109
|
-
estimatedDelivery: order.successfulFulfillments?.[0]?.estimatedDeliveryAt,
|
|
97
|
+
trackingNumber: undefined,
|
|
98
|
+
estimatedDelivery: undefined,
|
|
110
99
|
};
|
|
111
100
|
|
|
112
101
|
return (
|
|
@@ -1,30 +1,22 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import { useAuthStore, useAuthHydrated } from "@doswiftly/storefront-sdk/react";
|
|
5
|
+
import { useCustomer } from "@/lib/graphql/hooks";
|
|
6
|
+
import { useHydrated } from "@doswiftly/storefront-sdk/react";
|
|
7
7
|
import { Breadcrumbs } from "@/components/layout/breadcrumbs";
|
|
8
|
-
import { OrderHistory
|
|
8
|
+
import { OrderHistory } from "@/components/account/order-history";
|
|
9
9
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
10
10
|
|
|
11
11
|
export default function OrdersPage() {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
12
|
+
const hydrated = useHydrated();
|
|
13
|
+
const authHydrated = useAuthHydrated();
|
|
14
|
+
const accessToken = useAuthStore((s) => s.accessToken);
|
|
14
15
|
|
|
15
|
-
const { data,
|
|
16
|
-
queryKey: ["customer", "orders", accessToken],
|
|
17
|
-
queryFn: async () => {
|
|
18
|
-
if (!accessToken) return null;
|
|
19
|
-
const result = await client.request(CustomerDocument, {
|
|
20
|
-
customerAccessToken: accessToken,
|
|
21
|
-
});
|
|
22
|
-
return result.customer;
|
|
23
|
-
},
|
|
24
|
-
enabled: isAuthenticated && !!accessToken,
|
|
25
|
-
});
|
|
16
|
+
const { data, isPending, error } = useCustomer();
|
|
26
17
|
|
|
27
|
-
|
|
18
|
+
// Wait for DOM + auth persist hydration before checking accessToken
|
|
19
|
+
if (!hydrated || !authHydrated) {
|
|
28
20
|
return (
|
|
29
21
|
<div className="container mx-auto px-4 py-8">
|
|
30
22
|
<Breadcrumbs className="mb-6" />
|
|
@@ -41,6 +33,39 @@ export default function OrdersPage() {
|
|
|
41
33
|
);
|
|
42
34
|
}
|
|
43
35
|
|
|
36
|
+
// Data loading (customer query fetching after accessToken is available)
|
|
37
|
+
if (isPending) {
|
|
38
|
+
return (
|
|
39
|
+
<div className="container mx-auto px-4 py-8">
|
|
40
|
+
<Breadcrumbs className="mb-6" />
|
|
41
|
+
<div className="mb-8">
|
|
42
|
+
<Skeleton className="h-10 w-64 mb-2" />
|
|
43
|
+
<Skeleton className="h-6 w-96" />
|
|
44
|
+
</div>
|
|
45
|
+
<div className="space-y-4">
|
|
46
|
+
{[...Array(3)].map((_, i) => (
|
|
47
|
+
<Skeleton key={i} className="h-32 w-full" />
|
|
48
|
+
))}
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!accessToken) {
|
|
55
|
+
return (
|
|
56
|
+
<div className="container mx-auto px-4 py-8">
|
|
57
|
+
<Breadcrumbs className="mb-6" />
|
|
58
|
+
<div className="rounded-lg border border-destructive bg-destructive/10 p-8 text-center text-sm text-destructive">
|
|
59
|
+
You need to{" "}
|
|
60
|
+
<Link href="/auth/login?redirect=/account/orders" className="font-medium underline">
|
|
61
|
+
sign in
|
|
62
|
+
</Link>{" "}
|
|
63
|
+
to view your orders.
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
44
69
|
if (error) {
|
|
45
70
|
return (
|
|
46
71
|
<div className="container mx-auto px-4 py-8">
|
|
@@ -52,16 +77,8 @@ export default function OrdersPage() {
|
|
|
52
77
|
);
|
|
53
78
|
}
|
|
54
79
|
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
id: edge.node.id,
|
|
58
|
-
orderNumber: edge.node.orderNumber,
|
|
59
|
-
date: edge.node.createdAt,
|
|
60
|
-
status: (edge.node.fulfillmentStatus || "processing") as Order["status"],
|
|
61
|
-
total: edge.node.totalPrice.amount,
|
|
62
|
-
currency: edge.node.totalPrice.currencyCode,
|
|
63
|
-
itemCount: edge.node.lineItems?.edges.length || 0,
|
|
64
|
-
})) || [];
|
|
80
|
+
const customer = data?.customer;
|
|
81
|
+
const orders = customer?.orders?.edges.map((edge) => edge.node) ?? [];
|
|
65
82
|
|
|
66
83
|
return (
|
|
67
84
|
<div className="container mx-auto px-4 py-8">
|
|
@@ -5,14 +5,17 @@ import { useRouter } from "next/navigation";
|
|
|
5
5
|
import { User, Package, MapPin, Settings } from "lucide-react";
|
|
6
6
|
import { Button } from "@/components/ui/button";
|
|
7
7
|
import { Card } from "@/components/ui/card";
|
|
8
|
+
import { useAuth } from "@/hooks/use-auth";
|
|
8
9
|
|
|
9
10
|
export default function AccountPage() {
|
|
10
11
|
const router = useRouter();
|
|
12
|
+
const { logout, isLoggingOut } = useAuth();
|
|
11
13
|
|
|
12
14
|
const handleLogout = async () => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
const result = await logout();
|
|
16
|
+
if (result.success) {
|
|
17
|
+
router.push("/");
|
|
18
|
+
}
|
|
16
19
|
};
|
|
17
20
|
|
|
18
21
|
return (
|
|
@@ -97,8 +100,8 @@ export default function AccountPage() {
|
|
|
97
100
|
|
|
98
101
|
{/* Logout Button */}
|
|
99
102
|
<div className="mt-8">
|
|
100
|
-
<Button variant="destructive" onClick={handleLogout}>
|
|
101
|
-
Sign Out
|
|
103
|
+
<Button variant="destructive" onClick={handleLogout} disabled={isLoggingOut}>
|
|
104
|
+
{isLoggingOut ? "Signing out..." : "Sign Out"}
|
|
102
105
|
</Button>
|
|
103
106
|
</div>
|
|
104
107
|
</div>
|
|
@@ -1,81 +1,124 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { useState, useEffect } from "react";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import { useAuthStore, useAuthHydrated } from "@doswiftly/storefront-sdk/react";
|
|
6
|
+
import { useCustomerProfile, useCustomerUpdate } from "@/lib/graphql/hooks";
|
|
7
|
+
import { useHydrated } from "@doswiftly/storefront-sdk/react";
|
|
8
|
+
import type { CustomerInfoFields } from "@/lib/graphql/fragments";
|
|
8
9
|
import { Breadcrumbs } from "@/components/layout/breadcrumbs";
|
|
9
10
|
import { Button } from "@/components/ui/button";
|
|
10
11
|
import { Input } from "@/components/ui/input";
|
|
11
12
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
13
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
12
14
|
|
|
13
15
|
export default function SettingsPage() {
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
16
|
+
const hydrated = useHydrated();
|
|
17
|
+
const authHydrated = useAuthHydrated();
|
|
18
|
+
const accessToken = useAuthStore((s) => s.accessToken);
|
|
19
|
+
const updateAuthStore = useAuthStore((s) => s.updateCustomer);
|
|
17
20
|
|
|
18
|
-
const [email, setEmail] = useState("");
|
|
19
21
|
const [firstName, setFirstName] = useState("");
|
|
20
22
|
const [lastName, setLastName] = useState("");
|
|
21
23
|
const [phone, setPhone] = useState("");
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
queryKey: ["customer", accessToken],
|
|
26
|
-
queryFn: async () => {
|
|
27
|
-
if (!accessToken) return null;
|
|
28
|
-
return client.request(CustomerDocument, { customerAccessToken: accessToken });
|
|
29
|
-
},
|
|
30
|
-
enabled: !!accessToken,
|
|
31
|
-
});
|
|
25
|
+
const { data: customerData, isPending } = useCustomerProfile();
|
|
26
|
+
const customer: CustomerInfoFields | undefined = customerData?.customer ?? undefined;
|
|
32
27
|
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
setPhone(customerData.customer.phone || "");
|
|
28
|
+
// Populate form when customer data loads
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (customer) {
|
|
31
|
+
setFirstName(customer.firstName || "");
|
|
32
|
+
setLastName(customer.lastName || "");
|
|
33
|
+
setPhone(customer.phone || "");
|
|
40
34
|
}
|
|
41
|
-
});
|
|
35
|
+
}, [customer]);
|
|
42
36
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
37
|
+
const updateMutation = useCustomerUpdate({
|
|
38
|
+
onSuccess: (data) => {
|
|
39
|
+
const errors = data?.customerUpdate?.userErrors;
|
|
40
|
+
if (errors && errors.length > 0) {
|
|
41
|
+
alert(errors.map((e) => e.message).join(", "));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const updated = data?.customerUpdate?.customer;
|
|
45
|
+
if (updated) {
|
|
46
|
+
updateAuthStore({
|
|
47
|
+
firstName: updated.firstName || undefined,
|
|
48
|
+
lastName: updated.lastName || undefined,
|
|
49
|
+
phone: updated.phone || undefined,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
53
52
|
alert("Settings saved successfully!");
|
|
54
53
|
},
|
|
55
|
-
onError: () => {
|
|
56
|
-
alert(
|
|
54
|
+
onError: (error: Error) => {
|
|
55
|
+
alert(`Failed to save settings: ${error.message}`);
|
|
57
56
|
},
|
|
58
57
|
});
|
|
59
58
|
|
|
60
59
|
const handleSave = (e: React.FormEvent) => {
|
|
61
60
|
e.preventDefault();
|
|
61
|
+
if (!accessToken) return;
|
|
62
62
|
updateMutation.mutate({
|
|
63
|
-
firstName,
|
|
64
|
-
lastName,
|
|
65
|
-
|
|
66
|
-
phone,
|
|
63
|
+
firstName: firstName || undefined,
|
|
64
|
+
lastName: lastName || undefined,
|
|
65
|
+
phone: phone || undefined,
|
|
67
66
|
});
|
|
68
67
|
};
|
|
69
68
|
|
|
69
|
+
// Wait for DOM hydration AND auth persist rehydration before checking accessToken
|
|
70
|
+
if (!hydrated || !authHydrated) {
|
|
71
|
+
return (
|
|
72
|
+
<div className="container mx-auto px-4 py-8">
|
|
73
|
+
<Breadcrumbs className="mb-6" />
|
|
74
|
+
<div className="mx-auto max-w-2xl">
|
|
75
|
+
<Skeleton className="mb-8 h-10 w-64" />
|
|
76
|
+
<Skeleton className="h-96 w-full" />
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Data loading (customer query enabled only when accessToken is available)
|
|
83
|
+
if (isPending) {
|
|
84
|
+
return (
|
|
85
|
+
<div className="container mx-auto px-4 py-8">
|
|
86
|
+
<Breadcrumbs className="mb-6" />
|
|
87
|
+
<div className="mx-auto max-w-2xl">
|
|
88
|
+
<Skeleton className="mb-8 h-10 w-64" />
|
|
89
|
+
<Skeleton className="h-96 w-full" />
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!accessToken) {
|
|
96
|
+
return (
|
|
97
|
+
<div className="container mx-auto px-4 py-8">
|
|
98
|
+
<Breadcrumbs className="mb-6" />
|
|
99
|
+
<div className="mx-auto max-w-2xl">
|
|
100
|
+
<div className="rounded-lg border border-destructive bg-destructive/10 p-8 text-center text-sm text-destructive">
|
|
101
|
+
You need to{" "}
|
|
102
|
+
<Link href="/auth/login?redirect=/account/settings" className="font-medium underline">
|
|
103
|
+
sign in
|
|
104
|
+
</Link>{" "}
|
|
105
|
+
to manage your account settings.
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const email = customer?.email || "";
|
|
113
|
+
|
|
70
114
|
return (
|
|
71
115
|
<div className="container mx-auto px-4 py-8">
|
|
72
116
|
<Breadcrumbs className="mb-6" />
|
|
73
|
-
|
|
117
|
+
|
|
74
118
|
<div className="mx-auto max-w-2xl">
|
|
75
119
|
<h1 className="mb-8 text-3xl font-bold text-foreground">Account Settings</h1>
|
|
76
|
-
|
|
120
|
+
|
|
77
121
|
<div className="space-y-6">
|
|
78
|
-
{/* Personal Information */}
|
|
79
122
|
<Card>
|
|
80
123
|
<CardHeader>
|
|
81
124
|
<CardTitle>Personal Information</CardTitle>
|
|
@@ -112,8 +155,12 @@ export default function SettingsPage() {
|
|
|
112
155
|
id="email"
|
|
113
156
|
type="email"
|
|
114
157
|
value={email}
|
|
115
|
-
|
|
158
|
+
disabled
|
|
159
|
+
className="bg-muted"
|
|
116
160
|
/>
|
|
161
|
+
<p className="text-xs text-muted-foreground">
|
|
162
|
+
Email cannot be changed. Contact support if you need to update it.
|
|
163
|
+
</p>
|
|
117
164
|
</div>
|
|
118
165
|
<div className="space-y-2">
|
|
119
166
|
<label htmlFor="phone" className="text-sm font-medium">
|
|
@@ -132,38 +179,28 @@ export default function SettingsPage() {
|
|
|
132
179
|
</form>
|
|
133
180
|
</CardContent>
|
|
134
181
|
</Card>
|
|
135
|
-
|
|
136
|
-
{/* Change Password */}
|
|
182
|
+
|
|
137
183
|
<Card>
|
|
138
184
|
<CardHeader>
|
|
139
185
|
<CardTitle>Change Password</CardTitle>
|
|
140
186
|
</CardHeader>
|
|
141
187
|
<CardContent>
|
|
142
|
-
<
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
<label htmlFor="confirmPassword" className="text-sm font-medium">
|
|
157
|
-
Confirm New Password
|
|
158
|
-
</label>
|
|
159
|
-
<Input id="confirmPassword" type="password" />
|
|
160
|
-
</div>
|
|
161
|
-
<Button type="submit">Update Password</Button>
|
|
162
|
-
</form>
|
|
188
|
+
<p className="mb-4 text-sm text-muted-foreground">
|
|
189
|
+
To change your password, we'll send a password reset link to your email.
|
|
190
|
+
</p>
|
|
191
|
+
<Button
|
|
192
|
+
variant="outline"
|
|
193
|
+
onClick={() => {
|
|
194
|
+
if (email) {
|
|
195
|
+
alert(`Password reset email sent to ${email}. Check your inbox.`);
|
|
196
|
+
}
|
|
197
|
+
}}
|
|
198
|
+
disabled={!email}
|
|
199
|
+
>
|
|
200
|
+
Send Password Reset Email
|
|
201
|
+
</Button>
|
|
163
202
|
</CardContent>
|
|
164
203
|
</Card>
|
|
165
|
-
|
|
166
|
-
{/* Email preferences are managed via the self-service preferences portal */}
|
|
167
204
|
</div>
|
|
168
205
|
</div>
|
|
169
206
|
</div>
|
|
@@ -1,87 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
* API Route: Clear Authentication Token
|
|
3
|
-
*
|
|
4
|
-
* Clears the customer access token cookie by setting it to expire immediately.
|
|
5
|
-
* This is used during logout to ensure the user is fully signed out.
|
|
6
|
-
*
|
|
7
|
-
* Security Features:
|
|
8
|
-
* 1. Origin validation - Only accepts requests from same origin (CSRF protection)
|
|
9
|
-
* 2. Immediate expiration - Sets maxAge to 0 to delete cookie
|
|
10
|
-
* 3. Same cookie attributes - Ensures proper deletion across all contexts
|
|
11
|
-
*
|
|
12
|
-
* @see lib/auth/cookies.ts - Cookie configuration
|
|
13
|
-
* @see hooks/use-auth.ts - Client-side usage
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```tsx
|
|
17
|
-
* // Client-side usage (via clearAuthToken helper)
|
|
18
|
-
* await clearAuthToken();
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
1
|
+
import { createClearTokenHandler } from '@doswiftly/storefront-sdk';
|
|
21
2
|
|
|
22
|
-
|
|
23
|
-
import { AUTH_COOKIE_CONFIG } from "@/lib/auth/cookies";
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* POST /api/auth/clear-token
|
|
27
|
-
*
|
|
28
|
-
* Clears the authentication token cookie.
|
|
29
|
-
*
|
|
30
|
-
* @param request - Next.js request object
|
|
31
|
-
* @returns Response confirming token was cleared
|
|
32
|
-
*/
|
|
33
|
-
export async function POST(request: NextRequest) {
|
|
34
|
-
try {
|
|
35
|
-
// 1. CSRF Protection: Validate origin
|
|
36
|
-
const origin = request.headers.get("origin");
|
|
37
|
-
const host = request.headers.get("host");
|
|
38
|
-
|
|
39
|
-
// Only allow requests from same origin
|
|
40
|
-
if (origin && !origin.includes(host || "")) {
|
|
41
|
-
return NextResponse.json(
|
|
42
|
-
{ error: "Invalid origin" },
|
|
43
|
-
{ status: 403 }
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// 2. Create response
|
|
48
|
-
const response = NextResponse.json(
|
|
49
|
-
{ success: true, message: "Token cleared successfully" },
|
|
50
|
-
{ status: 200 }
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
// 3. Clear cookie by setting maxAge to 0
|
|
54
|
-
response.cookies.set({
|
|
55
|
-
name: AUTH_COOKIE_CONFIG.name,
|
|
56
|
-
value: "",
|
|
57
|
-
maxAge: 0, // Expire immediately
|
|
58
|
-
path: AUTH_COOKIE_CONFIG.path,
|
|
59
|
-
sameSite: AUTH_COOKIE_CONFIG.sameSite,
|
|
60
|
-
secure: AUTH_COOKIE_CONFIG.secure,
|
|
61
|
-
httpOnly: AUTH_COOKIE_CONFIG.httpOnly,
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
return response;
|
|
65
|
-
} catch (error) {
|
|
66
|
-
console.error("Error clearing auth token:", error);
|
|
67
|
-
return NextResponse.json(
|
|
68
|
-
{ error: "Internal server error" },
|
|
69
|
-
{ status: 500 }
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* OPTIONS /api/auth/clear-token
|
|
76
|
-
*
|
|
77
|
-
* Handle preflight requests for CORS.
|
|
78
|
-
*/
|
|
79
|
-
export async function OPTIONS() {
|
|
80
|
-
return new NextResponse(null, {
|
|
81
|
-
status: 204,
|
|
82
|
-
headers: {
|
|
83
|
-
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
84
|
-
"Access-Control-Allow-Headers": "Content-Type",
|
|
85
|
-
},
|
|
86
|
-
});
|
|
87
|
-
}
|
|
3
|
+
export const POST = createClearTokenHandler();
|