enh
This commit is contained in:
parent
489d0905c5
commit
b953774fbc
9 changed files with 114 additions and 29 deletions
|
|
@ -22,6 +22,7 @@ react-native. They are available in the common-ui as MyText, MyTextInput, MyTouc
|
|||
- Local imports last
|
||||
- Use absolute imports with path aliases when possible
|
||||
- imports from /packages/ui are aliased as `common-ui` in apps/user-ui and apps/admin-ui
|
||||
- For backend, use `@/*` to import from the backend root directory (e.g., `@/src/lib/file-name`)
|
||||
|
||||
### Error Handling
|
||||
- API errors handled via axios interceptors
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -7,6 +7,7 @@ import { authenticateUser } from "./middleware/auth.middleware";
|
|||
import { raiseComplaint } from "./uv-apis/user-rest.controller";
|
||||
import uploadHandler from "./lib/upload-handler";
|
||||
|
||||
|
||||
const router = Router();
|
||||
|
||||
// Health check endpoints (no auth required)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
|
|
@ -29,9 +29,10 @@
|
|||
"module": "commonjs",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./*"],
|
||||
"shared-types": ["../shared-types"],
|
||||
"@commonTypes": ["../../packages/ui/shared-types"],
|
||||
"@commonTypes/*": ["../../packages/ui/shared-types/*"]
|
||||
"@commonTypes/*": ["../../packages/ui/shared-types/*"],
|
||||
},
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [""], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
|
|
|
|||
|
|
@ -86,6 +86,20 @@ const RenderStore = ({
|
|||
|
||||
const headerColor = colors.secondaryPink;
|
||||
|
||||
// Format time range helper
|
||||
const formatTimeRange = (deliveryTime: string) => {
|
||||
const time = dayjs(deliveryTime);
|
||||
const endTime = time.add(1, 'hour');
|
||||
const startPeriod = time.format('A');
|
||||
const endPeriod = endTime.format('A');
|
||||
|
||||
if (startPeriod === endPeriod) {
|
||||
return `${time.format('h')}-${endTime.format('h')} ${startPeriod}`;
|
||||
} else {
|
||||
return `${time.format('h:mm')} ${startPeriod} - ${endTime.format('h:mm')} ${endPeriod}`;
|
||||
}
|
||||
};
|
||||
|
||||
export default function Dashboard() {
|
||||
const router = useRouter();
|
||||
const userDetails = useUserDetails();
|
||||
|
|
@ -479,12 +493,12 @@ export default function Dashboard() {
|
|||
<MyText
|
||||
style={tw`text-sm font-extrabold text-slate-900`}
|
||||
>
|
||||
{dayjs(slot.deliveryTime).format("h:mm A")}
|
||||
{formatTimeRange(slot.deliveryTime)}
|
||||
</MyText>
|
||||
<MyText
|
||||
style={tw`text-[11px] font-bold text-slate-500`}
|
||||
>
|
||||
{dayjs(slot.deliveryTime).format("ddd, MMM DD")}
|
||||
Delivery Slot
|
||||
</MyText>
|
||||
</View>
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,23 @@ const QuickDeliveryAddressSelector: React.FC<QuickDeliveryAddressSelectorProps>
|
|||
const defaultAddress = defaultAddressData?.data;
|
||||
const addresses = addressesData?.data || [];
|
||||
|
||||
// Format time range helper
|
||||
const formatTimeRange = (deliveryTime: string) => {
|
||||
const time = dayjs(deliveryTime);
|
||||
const endTime = time.add(1, 'hour');
|
||||
const startPeriod = time.format('A');
|
||||
const endPeriod = endTime.format('A');
|
||||
|
||||
let timeRange;
|
||||
if (startPeriod === endPeriod) {
|
||||
timeRange = `${time.format('h')}-${endTime.format('h')} ${startPeriod}`;
|
||||
} else {
|
||||
timeRange = `${time.format('h:mm')} ${startPeriod} - ${endTime.format('h:mm')} ${endPeriod}`;
|
||||
}
|
||||
|
||||
return `${time.format('ddd, DD MMM ')}${timeRange}`;
|
||||
};
|
||||
|
||||
// Find earliest slot for pre-selection
|
||||
const earliestSlot = slotsData?.slots?.sort((a, b) =>
|
||||
dayjs(a.deliveryTime).diff(dayjs(b.deliveryTime))
|
||||
|
|
@ -50,21 +67,23 @@ const QuickDeliveryAddressSelector: React.FC<QuickDeliveryAddressSelectorProps>
|
|||
}));
|
||||
|
||||
// Transform slots for display
|
||||
const slotOptions = slotsData?.slots?.map(slot => ({
|
||||
id: slot.id,
|
||||
deliveryTime: dayjs(slot.deliveryTime).format('MMM DD, h:mm A'),
|
||||
closeTime: dayjs(slot.freezeTime).format('h:mm A'),
|
||||
})) || [];
|
||||
const slotOptions = slotsData?.slots?.map(slot => {
|
||||
return {
|
||||
id: slot.id,
|
||||
deliveryTime: formatTimeRange(slot.deliveryTime),
|
||||
closeTime: dayjs(slot.freezeTime).format('h:mm A'),
|
||||
};
|
||||
}) || [];
|
||||
|
||||
// Get current selected slot display
|
||||
const getCurrentSlotDisplay = () => {
|
||||
if (isForFlashDelivery) return '30 minutes';
|
||||
if (slotId) {
|
||||
const slot = slotsData?.slots?.find(s => s.id === slotId);
|
||||
return slot ? dayjs(slot.deliveryTime).format('MMM DD, h:mm A') : 'Select time';
|
||||
return slot ? formatTimeRange(slot.deliveryTime) : 'Select time';
|
||||
}
|
||||
if (earliestSlot) {
|
||||
return dayjs(earliestSlot.deliveryTime).format('MMM DD, h:mm A');
|
||||
return formatTimeRange(earliestSlot.deliveryTime);
|
||||
}
|
||||
return 'Select time';
|
||||
};
|
||||
|
|
@ -118,7 +137,7 @@ const QuickDeliveryAddressSelector: React.FC<QuickDeliveryAddressSelectorProps>
|
|||
{/* Trigger Component with Separate Chevrons */}
|
||||
<View style={tw`bg-brand50 border border-brand100 rounded-lg p-3`}>
|
||||
|
||||
/* Regular Delivery Time Section */
|
||||
{/* Regular Delivery Time Section */}
|
||||
<MyTouchableOpacity
|
||||
onPress={() => setDialogOpen(true)}
|
||||
style={tw`flex-row items-center justify-between mb-2`}
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ const CompactProductCard = ({
|
|||
{item.marketPrice && Number(item.marketPrice) > Number(item.price) && (
|
||||
<MyText style={tw`text-gray-400 text-xs ml-1 line-through`}>₹{item.marketPrice}</MyText>
|
||||
)}
|
||||
<MyText style={tw`text-gray-600 text-xs ml-1`}>Quantity: <MyText style={tw`text-[#f81260] font-semibold`}>{formatQuantity(item.productQuantity || 1, item.unitNotation).display}</MyText></MyText>
|
||||
<MyText style={tw`text-gray-600 text-xs ml-1`}>Quantity: <MyText style={tw`text-[#f81260] font-semibold`}>{formatQuantity(item.productQuantity || 1, item.unit || item.unitNotation).display}</MyText></MyText>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -183,10 +183,26 @@ export default function CartPage({ isFlashDelivery = false }: CartPageProps) {
|
|||
const uniqueSlots = allSlots.filter(
|
||||
(slot, index, self) => index === self.findIndex((s) => s.id === slot.id)
|
||||
);
|
||||
|
||||
// Smart time window formatting function
|
||||
const formatTimeRange = (deliveryTime: string) => {
|
||||
const time = dayjs(deliveryTime);
|
||||
const endTime = time.add(1, 'hour');
|
||||
const startPeriod = time.format('A');
|
||||
const endPeriod = endTime.format('A');
|
||||
|
||||
let timeRange;
|
||||
if (startPeriod === endPeriod) {
|
||||
timeRange = `${time.format('h')}-${endTime.format('h')} ${startPeriod}`;
|
||||
} else {
|
||||
timeRange = `${time.format('h:mm')} ${startPeriod} - ${endTime.format('h:mm')} ${endPeriod}`;
|
||||
}
|
||||
|
||||
return `${time.format('ddd, DD MMM ')}${timeRange}`;
|
||||
};
|
||||
|
||||
return uniqueSlots.map((slot) => ({
|
||||
label: `Delivery: ${dayjs(slot.deliveryTime).format(
|
||||
"ddd DD MMM, h:mm a"
|
||||
)} - Close time: ${dayjs(slot.freezeTime).format("h:mm a")}`,
|
||||
label: `Delivery: ${formatTimeRange(slot.deliveryTime)} - Close time: ${dayjs(slot.freezeTime).format("h:mm a")}`,
|
||||
value: slot.id,
|
||||
}));
|
||||
}, [slotsData]);
|
||||
|
|
@ -195,12 +211,28 @@ export default function CartPage({ isFlashDelivery = false }: CartPageProps) {
|
|||
const getAvailableSlotsForProduct = React.useMemo(() => {
|
||||
return (productId: number) => {
|
||||
if (!slotsData || !slotsData[productId]) return [];
|
||||
return slotsData[productId].map((slot) => ({
|
||||
label: `Delivery: ${dayjs(slot.deliveryTime).format(
|
||||
"ddd DD MMM, h:mm a"
|
||||
)} - Close time: ${dayjs(slot.freezeTime).format("h:mm a")}`,
|
||||
value: slot.id,
|
||||
}));
|
||||
return slotsData[productId].map((slot) => {
|
||||
const formatTimeRange = (deliveryTime: string) => {
|
||||
const time = dayjs(deliveryTime);
|
||||
const endTime = time.add(1, 'hour');
|
||||
const startPeriod = time.format('A');
|
||||
const endPeriod = endTime.format('A');
|
||||
|
||||
let timeRange;
|
||||
if (startPeriod === endPeriod) {
|
||||
timeRange = `${time.format('h')}-${endTime.format('h')} ${startPeriod}`;
|
||||
} else {
|
||||
timeRange = `${time.format('h:mm')} ${startPeriod} - ${endTime.format('h:mm')} ${endPeriod}`;
|
||||
}
|
||||
|
||||
return `${time.format('ddd, DD MMM ')}${timeRange}`;
|
||||
};
|
||||
|
||||
return {
|
||||
label: `Delivery: ${formatTimeRange(slot.deliveryTime)} - Close time: ${dayjs(slot.freezeTime).format("h:mm a")}`,
|
||||
value: slot.id,
|
||||
};
|
||||
});
|
||||
};
|
||||
}, [slotsData]);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,23 @@ interface FloatingCartBarProps {
|
|||
setIsExpanded?: (value: boolean) => void;
|
||||
}
|
||||
|
||||
// Smart time window formatting function
|
||||
const formatTimeRange = (deliveryTime: string) => {
|
||||
const time = dayjs(deliveryTime);
|
||||
const endTime = time.add(1, 'hour');
|
||||
const startPeriod = time.format('A');
|
||||
const endPeriod = endTime.format('A');
|
||||
|
||||
let timeRange;
|
||||
if (startPeriod === endPeriod) {
|
||||
timeRange = `${time.format('h')}-${endTime.format('h')} ${startPeriod}`;
|
||||
} else {
|
||||
timeRange = `${time.format('h:mm')} ${startPeriod} - ${endTime.format('h:mm')} ${endPeriod}`;
|
||||
}
|
||||
|
||||
return `${time.format('ddd, DD MMM ')}${timeRange}`;
|
||||
};
|
||||
|
||||
const FloatingCartBar: React.FC<FloatingCartBarProps> = ({
|
||||
isFlashDelivery = false,
|
||||
isExpanded: controlledIsExpanded,
|
||||
|
|
@ -257,17 +274,17 @@ const FloatingCartBar: React.FC<FloatingCartBarProps> = ({
|
|||
<BottomDropdown
|
||||
label="Select Delivery Slot"
|
||||
value={item.slotId}
|
||||
options={(productSlotsMap.get(item.productId) || []).map(slotId => {
|
||||
options={(productSlotsMap.get(item.productId) || []).map(slotId => {
|
||||
const slot = slotsData.slots.find(s => s.id === slotId);
|
||||
return {
|
||||
label: slot ? dayjs(slot.deliveryTime).format("ddd, MMM DD • h:mm A") : "N/A",
|
||||
label: slot ? formatTimeRange(slot.deliveryTime) : "N/A",
|
||||
value: slotId,
|
||||
};
|
||||
})}
|
||||
onValueChange={(val) => {
|
||||
const newSlot = slotsData.slots.find(s => s.id === val);
|
||||
Alert.alert("Delivery Updated", `Scheduled for ${dayjs(newSlot?.deliveryTime).format("MMM DD, h:mm A")}`);
|
||||
}}
|
||||
onValueChange={(val) => {
|
||||
const newSlot = slotsData.slots.find(s => s.id === val);
|
||||
Alert.alert("Delivery Updated", `Scheduled for ${formatTimeRange(newSlot?.deliveryTime || '')}`);
|
||||
}}
|
||||
triggerComponent={({ onPress, displayText }) => (
|
||||
<MyTouchableOpacity
|
||||
onPress={onPress}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue