pickup time: intial commit

This commit is contained in:
2026-01-06 22:41:50 +03:00
parent ad036d1e64
commit ebe9928091
9 changed files with 553 additions and 6 deletions

View File

@@ -0,0 +1,340 @@
import { Button } from "antd";
import dayjs from "dayjs";
import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import Picker from "components/WheelPicker";
import { SERVER_DATE_FORMAT } from "utils/constants.ts";
interface PickupEstimateContentProps {
onSave: (date: string, time: string) => void;
onClose: () => void;
}
export default function PickupEstimateContent({
onSave,
onClose,
}: PickupEstimateContentProps) {
const { t } = useTranslation();
// Generate day options: Today, Tomorrow, then formatted dates (90 days total for scrolling)
const dayOptions = useMemo(() => {
const options = [];
const today = dayjs();
// Today
options.push({
value: "today",
label: "Today",
date: today.format(SERVER_DATE_FORMAT),
});
// Tomorrow
options.push({
value: "tomorrow",
label: "Tomorrow",
date: today.add(1, "day").format(SERVER_DATE_FORMAT),
});
// Next days with formatted dates (up to 90 days total for smooth scrolling)
for (let i = 2; i < 90; i++) {
const date = today.add(i, "day");
const formatted = date.toDate().toLocaleDateString("en-US", {
weekday: "long",
month: "long",
day: "numeric",
});
options.push({
value: `day-${i}`,
label: formatted,
date: date.format(SERVER_DATE_FORMAT),
});
}
return options;
}, []);
// Generate time options: Now, then time slots (5 items total)
const timeOptions = useMemo(() => {
const options = [];
const now = dayjs();
// Now option
options.push({
value: "now",
label: "Now",
time: now.format("HH:mm"),
});
// Calculate next 15-minute interval (always the next one, even if we're on a boundary)
const currentMinute = now.minute();
let nextMinute = Math.floor(currentMinute / 15) * 15 + 15;
let nextHour = now.hour();
if (nextMinute >= 60) {
nextMinute = 0;
nextHour += 1;
if (nextHour >= 24) {
nextHour = 0;
}
}
// Generate next 4 time slots (15-minute intervals)
let hour = nextHour;
let minute = nextMinute;
for (let i = 1; i < 48; i++) {
const time = dayjs().hour(hour).minute(minute).second(0);
const formatted = time.format("h:mm A");
options.push({
value: `time-${i}`,
label: formatted,
time: time.format("HH:mm"),
});
// Calculate next interval
minute += 15;
if (minute >= 60) {
minute = 0;
hour += 1;
if (hour >= 24) {
hour = 0;
}
}
}
return options;
}, []);
const [selectedDay, setSelectedDay] = useState<string>("today");
const [selectedTime, setSelectedTime] = useState<string>("now");
const handlePickerChange = (value: { day?: string; time?: string }) => {
console.log(value);
if (value.day !== undefined) {
setSelectedDay(value.day);
}
if (value.time !== undefined) {
setSelectedTime(value.time);
}
};
const handleSave = () => {
const selectedDayOption = dayOptions.find(
(opt) => opt.value === selectedDay,
);
const selectedTimeOption = timeOptions.find(
(opt) => opt.value === selectedTime,
);
if (selectedDayOption && selectedTimeOption) {
onSave(selectedDayOption.date, selectedTimeOption.time);
onClose();
}
};
const handleTouchStart = (e: React.TouchEvent<HTMLDivElement>) => {
e.stopPropagation();
};
const handleTouchMove = (e: React.TouchEvent<HTMLDivElement>) => {
e.stopPropagation();
};
const handleTouchEnd = (e: React.TouchEvent<HTMLDivElement>) => {
e.stopPropagation();
};
const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
};
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
};
const handleMouseUp = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
};
const handleWheel = (e: React.WheelEvent<HTMLDivElement>) => {
e.stopPropagation();
};
return (
<>
<div
style={{
marginTop: 30,
display: "flex",
flexDirection: "column",
}}
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
onWheel={handleWheel}
>
{/* Day and Time Pickers - Same Row */}
<div
style={{
display: "flex",
flexDirection: "row",
gap: "8px",
marginBottom: 30,
}}
>
{/* Day Picker */}
<div style={{ width: "60%" }}>
<Picker
value={{ day: selectedDay }}
onChange={(value) => handlePickerChange(value)}
width="100%"
height={250}
style={{
position: "relative",
display: "flex",
backgroundColor: "var(--secondary-background)",
overflow: "hidden",
width: "100%",
height: 250,
border: "none",
borderRadius: "8px",
}}
aria-selected={false}
>
<Picker.Column
name="day"
style={{
flex: 1,
backgroundColor: "var(--secondary-background)",
}}
>
{dayOptions.map((option) => (
<Picker.Item key={option.value} value={option.value}>
{({ selected }) => (
<div
style={{
fontWeight: selected ? "600" : "400",
color: selected
? "var(--foreground)"
: "var(--text-color-gray)",
fontSize: "16px",
padding: "9px 0",
textAlign: "center",
opacity: selected ? 1 : 0.7,
transition: "all 0.2s ease",
lineHeight: "1.2",
height: 36,
width: "100%",
backgroundColor: selected
? "var(--background)"
: "transparent",
borderRadius: selected ? "4px" : "0",
margin: selected ? "2px 4px" : "0",
}}
>
{option.label}
</div>
)}
</Picker.Item>
))}
</Picker.Column>
</Picker>
</div>
{/* Time Picker */}
<div style={{ width: "40%" }}>
<Picker
value={{ time: selectedTime }}
onChange={(value) => handlePickerChange(value)}
width="100%"
height={250}
style={{
position: "relative",
display: "flex",
backgroundColor: "var(--secondary-background)",
overflow: "hidden",
width: "100%",
height: 250,
border: "none",
borderRadius: "8px",
}}
aria-selected={false}
>
<Picker.Column
name="time"
style={{
flex: 1,
backgroundColor: "var(--secondary-background)",
}}
>
{timeOptions.map((option) => (
<Picker.Item key={option.value} value={option.value}>
{({ selected }) => (
<div
style={{
fontWeight: selected ? "600" : "400",
color: selected
? "var(--foreground)"
: "var(--text-color-gray)",
fontSize: "16px",
padding: "9px 0",
textAlign: "center",
opacity: selected ? 1 : 0.7,
transition: "all 0.2s ease",
lineHeight: "1.2",
height: 36,
width: "100%",
backgroundColor: selected
? "var(--background)"
: "transparent",
borderRadius: selected ? "4px" : "0",
margin: selected ? "2px 4px" : "0",
}}
>
{option.label}
</div>
)}
</Picker.Item>
))}
</Picker.Column>
</Picker>
</div>
</div>
</div>
{/* Save Button */}
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
<Button
type="primary"
onClick={handleSave}
style={{
width: "100%",
height: 48,
fontSize: 16,
fontWeight: 600,
backgroundColor: "var(--primary)",
border: "none",
}}
>
{t("checkout.scheduled")}
</Button>
<Button
onClick={handleSave}
style={{
width: "100%",
height: 48,
fontSize: 16,
fontWeight: 600,
border: "1px solid ##C0BFC4",
}}
>
{t("checkout.pickupNow")}
</Button>
</div>
</>
);
}