Skip to content

Commit 8861498

Browse files
authored
Merge pull request #956 from evershopcommerce/fix_shipping_note_955
fix: Shipping note is not showing on the checkout page #955
2 parents a85a6f6 + e8b47fc commit 8861498

4 files changed

Lines changed: 77 additions & 6 deletions

File tree

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import {
2+
Card,
3+
CardContent,
4+
CardHeader,
5+
CardTitle
6+
} from '@components/common/ui/Card.js';
7+
import { Textarea } from '@components/common/ui/Textarea.js';
8+
import { useCartState } from '@components/frontStore/cart/CartContext.js';
9+
import { useCheckoutDispatch } from '@components/frontStore/checkout/CheckoutContext.js';
10+
import { _ } from '@evershop/evershop/lib/locale/translate/_';
11+
import { NotebookPen } from 'lucide-react';
12+
import React, { useEffect, useState } from 'react';
13+
14+
export function ShippingNote() {
15+
const { updateCheckoutData } = useCheckoutDispatch();
16+
const { data: cart } = useCartState();
17+
const [note, setNote] = useState(cart?.shippingNote ?? '');
18+
19+
// This component lives outside the checkout <Form>, so it is NOT a
20+
// react-hook-form field — using TextareaField here throws because
21+
// useFormContext() is null. The note reaches the order purely through
22+
// checkoutData: the unified checkout POST sends `checkoutData`, and the
23+
// server's checkout service reads `data.note` and persists it as the cart's
24+
// `shipping_note` field.
25+
useEffect(() => {
26+
updateCheckoutData({ note });
27+
}, [note]);
28+
29+
return (
30+
<div className="checkout-shipping-note mb-5">
31+
<Card>
32+
<CardHeader>
33+
<CardTitle>
34+
<div className="flex items-center gap-2">
35+
<NotebookPen className="w-5 h-5" />
36+
<span>{_('Order Note')}</span>
37+
</div>
38+
</CardTitle>
39+
</CardHeader>
40+
<CardContent>
41+
<Textarea
42+
value={note}
43+
onChange={(e) => setNote(e.target.value)}
44+
placeholder={_('Add a note to your order')}
45+
rows={3}
46+
/>
47+
</CardContent>
48+
</Card>
49+
</div>
50+
);
51+
}

packages/evershop/src/modules/checkout/pages/frontStore/checkout/Checkout.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,26 @@ import { CheckoutProvider } from '@components/frontStore/checkout/CheckoutContex
88
import { ContactInformation } from '@components/frontStore/checkout/ContactInformation.js';
99
import { Payment } from '@components/frontStore/checkout/Payment.js';
1010
import { Shipment } from '@components/frontStore/checkout/Shipment.js';
11+
import { ShippingNote } from '@components/frontStore/checkout/ShippingNote.js';
12+
import { _ } from '@evershop/evershop/lib/locale/translate/_';
1113
import React from 'react';
12-
import './Checkout.scss';
1314
import { useForm } from 'react-hook-form';
14-
import { _ } from '@evershop/evershop/lib/locale/translate/_';
15+
import './Checkout.scss';
1516

1617
interface CheckoutPageProps {
1718
placeOrderApi: string;
1819
getPaymentMethodApi: string;
1920
getShippingMethodApi: string;
2021
checkoutSuccessUrl: string;
22+
setting: {
23+
showShippingNote: boolean;
24+
};
2125
}
2226

2327
export default function CheckoutPage({
2428
placeOrderApi,
25-
checkoutSuccessUrl
29+
checkoutSuccessUrl,
30+
setting: { showShippingNote }
2631
}: CheckoutPageProps) {
2732
const [disabled, setDisabled] = React.useState(false);
2833
const form = useForm({
@@ -54,6 +59,7 @@ export default function CheckoutPage({
5459
<Area id="checkoutFormAfter" noOuter />
5560
</Form>
5661
<div>
62+
{showShippingNote && <ShippingNote />}
5763
<CartItems>
5864
{({ items, loading, showPriceIncludingTax }) => (
5965
<CartSummaryItemsList
@@ -79,5 +85,8 @@ export const query = `
7985
query Query {
8086
placeOrderApi: url(routeId: "createOrder")
8187
checkoutSuccessUrl: url(routeId: "checkoutSuccess")
88+
setting {
89+
showShippingNote
90+
}
8291
}
8392
`;

packages/evershop/src/modules/checkout/services/checkout.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,14 @@ const _checkout = async function checkout(
9393
});
9494
}
9595

96-
// Add Note (use cart.setData)
97-
if (data.note) {
98-
await cart.setData('note', data.note);
96+
// Add shipping note. The registered cart field is `shipping_note` (see
97+
// registerCartBaseFields.js) and `orderCreator` copies it to the order's
98+
// `shipping_note` column via cart.exportData(). NOTE: the key must be
99+
// `shipping_note`, not `note` — DataObject.setData throws
100+
// "Field note not existed" for an unregistered key, which would abort the
101+
// whole order placement the moment a note is submitted.
102+
if (typeof data.note === 'string') {
103+
await cart.setData('shipping_note', data.note);
99104
}
100105
await saveCart(cart);
101106
const order = await createOrder(cart);

packages/evershop/src/types/checkoutData.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,11 @@ export interface CheckoutData {
2323
* surfaced as "Selected shipping method is no longer available."
2424
*/
2525
shippingProvider?: string;
26+
/**
27+
* Free-form note the customer adds to the order on the checkout page.
28+
* Persisted to the cart's `shipping_note` field, which `orderCreator`
29+
* copies to the order's `shipping_note` column via cart.exportData().
30+
*/
31+
note?: string;
2632
[key: string]: unknown;
2733
}

0 commit comments

Comments
 (0)