feat: delivery/pickup switching in admin card + address field
- Added delivery address input field in manual agreement form (visible when delivery type) - Pickup switching clears delivery_address in DB, delivery switching preserves/updates it - useOrderGroups passes deliveryType, deliveryAddress, pickupDate, pickupTimeSlot to API - orderGroupRepository: updateOrderGroupDeliveryChoice now handles delivery_type and address - Pickup orders: address cleared, pickup_date/pickup_time_slot saved - Delivery orders: address saved, pickup fields cleared - Updated tests to match new payload structure
This commit is contained in:
parent
9aef4d49c0
commit
498faca24d
|
|
@ -637,8 +637,8 @@ export const OrderDetailPanel = ({
|
||||||
deliveryDate: deliveryType === "pickup" ? pickupDate : deliveryDate,
|
deliveryDate: deliveryType === "pickup" ? pickupDate : deliveryDate,
|
||||||
deliveryTime: deliveryType === "pickup" ? pickupTimeSlot : deliveryTime,
|
deliveryTime: deliveryType === "pickup" ? pickupTimeSlot : deliveryTime,
|
||||||
deliveryType,
|
deliveryType,
|
||||||
...(deliveryType === "pickup" ? { pickupDate, pickupTimeSlot } : {}),
|
...(deliveryType === "pickup" ? { pickupDate, pickupTimeSlot, deliveryAddress: "" } : {}),
|
||||||
...(deliveryType === "delivery" && deliveryAddress.trim() ? { deliveryAddress: deliveryAddress.trim() } : {}),
|
...(deliveryType === "delivery" ? { deliveryAddress: deliveryAddress.trim() } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result?.success) {
|
if (result?.success) {
|
||||||
|
|
@ -866,6 +866,20 @@ export const OrderDetailPanel = ({
|
||||||
<p>Начиная с 3-го рабочего дня — <strong>300 ₽/день</strong> платного хранения.</p>
|
<p>Начиная с 3-го рабочего дня — <strong>300 ₽/день</strong> платного хранения.</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{deliveryType === "delivery" && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-text-muted)]">
|
||||||
|
Адрес доставки
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={deliveryAddress}
|
||||||
|
onChange={(e) => setDeliveryAddress(e.target.value)}
|
||||||
|
placeholder="Введите адрес доставки"
|
||||||
|
className="w-full rounded-2xl border border-[var(--color-border)] bg-[var(--color-surface)] px-4 py-3 text-sm !text-[var(--color-text)] placeholder:text-[var(--color-text-muted)] focus:border-[var(--color-accent)] focus:outline-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{isDeliveryAgreed && !isEditingDate ? (
|
{isDeliveryAgreed && !isEditingDate ? (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="rounded-[24px] border border-[rgba(18,128,92,0.35)] bg-[var(--color-accent-soft)] p-4 !text-[var(--color-text)]">
|
<div className="rounded-[24px] border border-[rgba(18,128,92,0.35)] bg-[var(--color-accent-soft)] p-4 !text-[var(--color-text)]">
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,10 @@ export const useOrderGroups = () => {
|
||||||
orderGroupId,
|
orderGroupId,
|
||||||
deliveryDate,
|
deliveryDate,
|
||||||
deliveryTime,
|
deliveryTime,
|
||||||
|
deliveryType,
|
||||||
|
deliveryAddress,
|
||||||
|
pickupDate,
|
||||||
|
pickupTimeSlot,
|
||||||
}) => {
|
}) => {
|
||||||
setIsSavingDeliveryChoice(true);
|
setIsSavingDeliveryChoice(true);
|
||||||
|
|
||||||
|
|
@ -125,6 +129,10 @@ export const useOrderGroups = () => {
|
||||||
orderGroupId,
|
orderGroupId,
|
||||||
deliveryDate,
|
deliveryDate,
|
||||||
deliveryTime,
|
deliveryTime,
|
||||||
|
deliveryType,
|
||||||
|
deliveryAddress,
|
||||||
|
pickupDate,
|
||||||
|
pickupTimeSlot,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
|
|
|
||||||
|
|
@ -258,25 +258,36 @@ export const updateOrderGroupDeliveryChoice = async ({
|
||||||
deliveryDate,
|
deliveryDate,
|
||||||
deliveryTime,
|
deliveryTime,
|
||||||
deliveryType,
|
deliveryType,
|
||||||
|
deliveryAddress,
|
||||||
pickupDate,
|
pickupDate,
|
||||||
pickupTimeSlot,
|
pickupTimeSlot,
|
||||||
}) => {
|
}) => {
|
||||||
return safeSupabaseCall(async () => {
|
return safeSupabaseCall(async () => {
|
||||||
const client = requireSupabase();
|
const client = requireSupabase();
|
||||||
const effectiveDeliveryStatus = deliveryType === "pickup" ? "pickup" : "agreed";
|
const effectiveDeliveryStatus = deliveryType === "pickup" ? "pickup" : "agreed";
|
||||||
|
const updatePayload = {
|
||||||
|
delivery_status: effectiveDeliveryStatus,
|
||||||
|
delivery_date: deliveryDate,
|
||||||
|
delivery_time: deliveryTime,
|
||||||
|
delivery_type: deliveryType || "delivery",
|
||||||
|
delivery_date_source: "manual",
|
||||||
|
notification_status: "confirmed",
|
||||||
|
updated_at: new Date().toISOString(),
|
||||||
|
};
|
||||||
|
if (deliveryType === "pickup") {
|
||||||
|
updatePayload.pickup_date = pickupDate || null;
|
||||||
|
updatePayload.pickup_time_slot = pickupTimeSlot || null;
|
||||||
|
updatePayload.delivery_address = "";
|
||||||
|
} else {
|
||||||
|
updatePayload.pickup_date = null;
|
||||||
|
updatePayload.pickup_time_slot = null;
|
||||||
|
if (deliveryAddress !== undefined) {
|
||||||
|
updatePayload.delivery_address = deliveryAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
const updateResult = await client
|
const updateResult = await client
|
||||||
.from("order_groups")
|
.from("order_groups")
|
||||||
.update({
|
.update(updatePayload)
|
||||||
delivery_status: effectiveDeliveryStatus,
|
|
||||||
delivery_date: deliveryDate,
|
|
||||||
delivery_time: deliveryTime,
|
|
||||||
delivery_type: deliveryType || "delivery",
|
|
||||||
pickup_date: deliveryType === "pickup" ? pickupDate : null,
|
|
||||||
pickup_time_slot: deliveryType === "pickup" ? pickupTimeSlot : null,
|
|
||||||
delivery_date_source: "manual",
|
|
||||||
notification_status: "confirmed",
|
|
||||||
updated_at: new Date().toISOString(),
|
|
||||||
})
|
|
||||||
.eq("id", orderGroupId);
|
.eq("id", orderGroupId);
|
||||||
|
|
||||||
if (updateResult.error) {
|
if (updateResult.error) {
|
||||||
|
|
|
||||||
|
|
@ -158,15 +158,16 @@ describe("updateOrderGroupDeliveryChoice", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(fromMock).toHaveBeenCalledWith("order_groups");
|
expect(fromMock).toHaveBeenCalledWith("order_groups");
|
||||||
expect(updateMock).toHaveBeenCalledWith({
|
expect(updateMock).toHaveBeenCalledWith(expect.objectContaining({
|
||||||
delivery_status: "agreed",
|
delivery_status: "agreed",
|
||||||
delivery_date: "2026-05-13",
|
delivery_date: "2026-05-13",
|
||||||
delivery_time: "Первая половина дня",
|
delivery_time: "Первая половина дня",
|
||||||
|
delivery_type: "delivery",
|
||||||
notification_status: "confirmed",
|
notification_status: "confirmed",
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
});
|
}));
|
||||||
expect(eqMock).toHaveBeenCalledWith("id", "group-id");
|
expect(eqMock).toHaveBeenCalledWith("id", "group-id");
|
||||||
expect(selectMock).toHaveBeenCalledWith("id, group_key, order_numbers, status, delivery_status, sms_sent_at, created_at, updated_at, created_from_exchange_at, source_key, customer_name, customer_phone, customer_phone_normalized, customer_date, orders_total, orders_ready, orders_not_ready, source_orders, order_list, order_list_structured, delivery_invitation_id, delivery_link, notification_status, sms_attempts, first_sms_sent_at, second_sms_sent_at, last_sms_error, next_notification_check_at, delivery_date, delivery_time, delivery_address, manual_confirmation_at, paid_storage_at, assigned_driver_id, assigned_driver:users!order_groups_assigned_driver_id_fkey(id, name)");
|
expect(selectMock).toHaveBeenCalledWith(expect.stringContaining("delivery_type, pickup_date, pickup_time_slot"));
|
||||||
expect(singleMock).toHaveBeenCalledTimes(1);
|
expect(singleMock).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue