This commit is contained in:
shafi54 2026-01-25 20:07:25 +05:30
parent 489d0905c5
commit b953774fbc
9 changed files with 114 additions and 29 deletions

View file

@ -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

View file

@ -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)

View file

@ -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'. */

View file

@ -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>

View file

@ -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`}

View file

@ -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>

View file

@ -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]);

View file

@ -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}