Edited layout of mmddyyyy and time dropdown. Changed algorithm for determining pricing so that it choosest the cheapest option for users

This commit is contained in:
jackiettran
2026-01-01 14:46:40 -05:00
parent 3d0e553620
commit fd2312fe47
3 changed files with 650 additions and 210 deletions

View File

@@ -0,0 +1,376 @@
const RentalDurationCalculator = require("../../../utils/rentalDurationCalculator");
describe("RentalDurationCalculator - Hybrid Pricing", () => {
// Helper to create ISO date strings
const date = (dateStr, time = "10:00") => {
return `2024-01-${dateStr.padStart(2, "0")}T${time}:00.000Z`;
};
describe("calculateRentalCost", () => {
describe("Basic single-tier pricing", () => {
test("should calculate hourly rate for short rentals", () => {
const item = { pricePerHour: 10 };
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("01", "13:00"),
item
);
expect(result).toBe(30); // 3 hours * $10
});
test("should calculate daily rate for exact day rentals", () => {
const item = { pricePerDay: 50 };
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("03", "10:00"),
item
);
expect(result).toBe(100); // 2 days * $50
});
test("should calculate weekly rate for exact week rentals", () => {
const item = { pricePerWeek: 200 };
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("15", "10:00"),
item
);
expect(result).toBe(400); // 2 weeks * $200
});
test("should calculate monthly rate for exact month rentals", () => {
const item = { pricePerMonth: 600 };
const result = RentalDurationCalculator.calculateRentalCost(
"2024-01-01T10:00:00.000Z",
"2024-03-01T10:00:00.000Z", // 60 days = exactly 2 months (using 30-day months)
item
);
expect(result).toBe(1200); // 2 months * $600
});
});
describe("Hybrid day + hours pricing", () => {
test("should combine day and hours for 26-hour rental", () => {
const item = { pricePerDay: 50, pricePerHour: 10 };
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "15:00"),
date("02", "17:00"), // 26 hours
item
);
expect(result).toBe(70); // 1 day ($50) + 2 hours ($20)
});
test("should combine day and hours for 27-hour rental", () => {
const item = { pricePerDay: 50, pricePerHour: 10 };
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("02", "13:00"), // 27 hours
item
);
expect(result).toBe(80); // 1 day ($50) + 3 hours ($30)
});
test("should choose cheaper option - round up when hourly is expensive", () => {
// 25 hours: daily = $40, hourly = $50
// Hybrid: 1 day ($40) + 1 hour ($50) = $90
// Round-up: 2 days ($80)
// Expected: $80 (round-up wins)
const item = { pricePerDay: 40, pricePerHour: 50 };
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("02", "11:00"), // 25 hours
item
);
expect(result).toBe(80); // 2 days (cheaper than 1d + 1h)
});
test("should choose cheaper option - hybrid when hourly is cheap", () => {
// 25 hours: daily = $50, hourly = $5
// Hybrid: 1 day ($50) + 1 hour ($5) = $55
// Round-up: 2 days ($100)
// Expected: $55 (hybrid wins)
const item = { pricePerDay: 50, pricePerHour: 5 };
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("02", "11:00"), // 25 hours
item
);
expect(result).toBe(55); // 1 day + 1 hour (cheaper)
});
});
describe("Hybrid week + days pricing", () => {
test("should combine week and days for 10-day rental", () => {
const item = { pricePerWeek: 200, pricePerDay: 50 };
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("11", "10:00"), // 10 days
item
);
expect(result).toBe(350); // 1 week ($200) + 3 days ($150)
});
test("should combine week and days for 9-day rental", () => {
const item = { pricePerWeek: 200, pricePerDay: 50 };
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("10", "10:00"), // 9 days
item
);
expect(result).toBe(300); // 1 week ($200) + 2 days ($100)
});
test("should round up to 2 weeks when daily cost exceeds week", () => {
// 10 days: weekly = $100, daily = $50
// Hybrid: 1 week ($100) + 3 days ($150) = $250
// Round-up: 2 weeks ($200)
// Expected: $200 (round-up wins)
const item = { pricePerWeek: 100, pricePerDay: 50 };
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("11", "10:00"), // 10 days
item
);
expect(result).toBe(200); // 2 weeks (cheaper)
});
});
describe("Hybrid month + weeks + days pricing", () => {
test("should combine month, week, and days for 38-day rental", () => {
const item = { pricePerMonth: 600, pricePerWeek: 200, pricePerDay: 50 };
const result = RentalDurationCalculator.calculateRentalCost(
"2024-01-01T10:00:00.000Z",
"2024-02-08T10:00:00.000Z", // 38 days
item
);
expect(result).toBe(850); // 1 month ($600) + 1 week ($200) + 1 day ($50)
});
test("should combine month and days for 35-day rental without weekly", () => {
const item = { pricePerMonth: 600, pricePerDay: 50 };
const result = RentalDurationCalculator.calculateRentalCost(
"2024-01-01T10:00:00.000Z",
"2024-02-05T10:00:00.000Z", // 35 days
item
);
expect(result).toBe(850); // 1 month ($600) + 5 days ($250)
});
});
describe("Full hybrid: month + week + day + hour", () => {
test("should combine all tiers for complex duration", () => {
const item = {
pricePerMonth: 600,
pricePerWeek: 200,
pricePerDay: 50,
pricePerHour: 10,
};
// 38 days + 5 hours
const result = RentalDurationCalculator.calculateRentalCost(
"2024-01-01T10:00:00.000Z",
"2024-02-08T15:00:00.000Z",
item
);
// 1 month + 1 week + 1 day + 5 hours = $600 + $200 + $50 + $50 = $900
expect(result).toBe(900);
});
});
describe("Missing tier fallback", () => {
test("should round up to days when no hourly rate", () => {
const item = { pricePerDay: 50 }; // No hourly
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "15:00"),
date("02", "17:00"), // 26 hours
item
);
expect(result).toBe(100); // 2 days (rounded up)
});
test("should round up to weeks when no daily rate", () => {
const item = { pricePerWeek: 200 }; // No daily
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("10", "10:00"), // 9 days
item
);
expect(result).toBe(400); // 2 weeks (rounded up)
});
test("should round up to months when no weekly or daily rate", () => {
const item = { pricePerMonth: 600 }; // Only monthly
const result = RentalDurationCalculator.calculateRentalCost(
"2024-01-01T10:00:00.000Z",
"2024-02-15T10:00:00.000Z", // 45 days
item
);
expect(result).toBe(1200); // 2 months (rounded up)
});
test("should use hourly only when no larger tiers", () => {
const item = { pricePerHour: 10 }; // Only hourly
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("03", "10:00"), // 48 hours
item
);
expect(result).toBe(480); // 48 hours * $10
});
});
describe("Edge cases", () => {
test("should return 0 for zero duration", () => {
const item = { pricePerDay: 50 };
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("01", "10:00"),
item
);
expect(result).toBe(0);
});
test("should return 0 for negative duration", () => {
const item = { pricePerDay: 50 };
const result = RentalDurationCalculator.calculateRentalCost(
date("02", "10:00"),
date("01", "10:00"), // End before start
item
);
expect(result).toBe(0);
});
test("should return 0 for free items (no pricing)", () => {
const item = {}; // No pricing
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("05", "10:00"),
item
);
expect(result).toBe(0);
});
test("should return 0 when all prices are 0", () => {
const item = {
pricePerHour: 0,
pricePerDay: 0,
pricePerWeek: 0,
pricePerMonth: 0,
};
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("05", "10:00"),
item
);
expect(result).toBe(0);
});
test("should handle decimal prices", () => {
const item = { pricePerHour: 5.5 };
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("01", "13:00"), // 3 hours
item
);
expect(result).toBe(16.5); // 3 * $5.50
});
test("should round result to 2 decimal places", () => {
const item = { pricePerHour: 3.33 };
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "10:00"),
date("01", "13:00"), // 3 hours
item
);
expect(result).toBe(9.99); // 3 * $3.33
});
test("should handle string prices in item", () => {
const item = { pricePerDay: "50", pricePerHour: "10" };
const result = RentalDurationCalculator.calculateRentalCost(
date("01", "15:00"),
date("02", "17:00"), // 26 hours
item
);
expect(result).toBe(70); // 1 day + 2 hours
});
test("should handle very short rentals (less than 1 hour)", () => {
const item = { pricePerHour: 10 };
const result = RentalDurationCalculator.calculateRentalCost(
"2024-01-01T10:00:00.000Z",
"2024-01-01T10:30:00.000Z", // 30 minutes
item
);
expect(result).toBe(10); // Rounds up to 1 hour
});
});
describe("Real-world scenarios", () => {
test("Scenario: Tool rental 3 days 4 hours", () => {
const item = { pricePerDay: 25, pricePerHour: 5 };
const result = RentalDurationCalculator.calculateRentalCost(
"2024-01-01T08:00:00.000Z",
"2024-01-04T12:00:00.000Z", // 3 days + 4 hours
item
);
expect(result).toBe(95); // 3 days ($75) + 4 hours ($20)
});
test("Scenario: Equipment rental 2 weeks 3 days", () => {
const item = { pricePerWeek: 100, pricePerDay: 20 };
const result = RentalDurationCalculator.calculateRentalCost(
"2024-01-01T10:00:00.000Z",
"2024-01-18T10:00:00.000Z", // 17 days = 2 weeks + 3 days
item
);
expect(result).toBe(260); // 2 weeks ($200) + 3 days ($60)
});
test("Scenario: Long-term rental 2 months 1 week", () => {
const item = { pricePerMonth: 500, pricePerWeek: 150 };
const result = RentalDurationCalculator.calculateRentalCost(
"2024-01-01T10:00:00.000Z",
"2024-03-08T10:00:00.000Z", // ~67 days = 2 months + 1 week
item
);
expect(result).toBe(1150); // 2 months ($1000) + 1 week ($150)
});
});
});
describe("buildPricingTiers", () => {
test("should return empty array for items with no pricing", () => {
const item = {};
const tiers = RentalDurationCalculator.buildPricingTiers(item);
expect(tiers).toHaveLength(0);
});
test("should build tiers from largest to smallest", () => {
const item = {
pricePerMonth: 600,
pricePerWeek: 200,
pricePerDay: 50,
pricePerHour: 10,
};
const tiers = RentalDurationCalculator.buildPricingTiers(item);
expect(tiers).toHaveLength(4);
expect(tiers[0].name).toBe("month");
expect(tiers[1].name).toBe("week");
expect(tiers[2].name).toBe("day");
expect(tiers[3].name).toBe("hour");
});
test("should skip tiers with 0 or null pricing", () => {
const item = {
pricePerMonth: 0,
pricePerWeek: null,
pricePerDay: 50,
pricePerHour: 10,
};
const tiers = RentalDurationCalculator.buildPricingTiers(item);
expect(tiers).toHaveLength(2);
expect(tiers[0].name).toBe("day");
expect(tiers[1].name).toBe("hour");
});
});
});

View File

@@ -1,61 +1,143 @@
/**
* Rental Duration Calculator with Hybrid Pricing
*
* Finds the optimal (cheapest) combination of pricing tiers for any rental duration.
* Supports combining hours + days + weeks + months for best pricing.
*
* Example: 26 hours with $10/hr and $50/day
* - Old logic: 2 days × $50 = $100
* - New logic: 1 day × $50 + 2 hours × $10 = $70
*/
class RentalDurationCalculator { class RentalDurationCalculator {
// Time constants in milliseconds
static HOUR_MS = 60 * 60 * 1000;
static DAY_MS = 24 * 60 * 60 * 1000;
static WEEK_MS = 7 * 24 * 60 * 60 * 1000;
static MONTH_MS = 30 * 24 * 60 * 60 * 1000;
/**
* Build available pricing tiers from item, sorted largest to smallest
* @param {Object} item - Item object with pricing information
* @returns {Array} Array of {name, price, durationMs} sorted largest to smallest
*/
static buildPricingTiers(item) {
const tiers = [];
if (item.pricePerMonth && Number(item.pricePerMonth) > 0) {
tiers.push({
name: "month",
price: Number(item.pricePerMonth),
durationMs: this.MONTH_MS,
});
}
if (item.pricePerWeek && Number(item.pricePerWeek) > 0) {
tiers.push({
name: "week",
price: Number(item.pricePerWeek),
durationMs: this.WEEK_MS,
});
}
if (item.pricePerDay && Number(item.pricePerDay) > 0) {
tiers.push({
name: "day",
price: Number(item.pricePerDay),
durationMs: this.DAY_MS,
});
}
if (item.pricePerHour && Number(item.pricePerHour) > 0) {
tiers.push({
name: "hour",
price: Number(item.pricePerHour),
durationMs: this.HOUR_MS,
});
}
return tiers;
}
/**
* Recursively calculate optimal price for remaining duration
* Uses greedy approach: try largest tier first, then handle remainder with smaller tiers
* Compares hybrid price vs round-up price and returns the cheaper option
*
* @param {number} remainingMs - Remaining duration in milliseconds
* @param {Array} tiers - Available pricing tiers (largest to smallest)
* @param {number} tierIndex - Current tier being considered
* @returns {number} Optimal price for this duration
*/
static calculateOptimalForDuration(remainingMs, tiers, tierIndex = 0) {
// Base case: no remaining time
if (remainingMs <= 0) {
return 0;
}
// Base case: no more tiers available - round up with smallest available tier
if (tierIndex >= tiers.length) {
const smallestTier = tiers[tiers.length - 1];
const unitsNeeded = Math.ceil(remainingMs / smallestTier.durationMs);
return unitsNeeded * smallestTier.price;
}
const currentTier = tiers[tierIndex];
const completeUnits = Math.floor(remainingMs / currentTier.durationMs);
const remainder = remainingMs - completeUnits * currentTier.durationMs;
if (completeUnits > 0) {
// Option 1: Use complete units of current tier + handle remainder with smaller tiers
const currentCost = completeUnits * currentTier.price;
const remainderCost = this.calculateOptimalForDuration(
remainder,
tiers,
tierIndex + 1
);
const hybridCost = currentCost + remainderCost;
// Option 2: Round up to one more unit of current tier (may be cheaper if remainder cost is high)
const roundUpCost = (completeUnits + 1) * currentTier.price;
// Return the cheaper option when there's a remainder to handle
return remainder > 0 ? Math.min(hybridCost, roundUpCost) : currentCost;
} else {
// Duration too small for this tier, try next smaller tier
return this.calculateOptimalForDuration(remainingMs, tiers, tierIndex + 1);
}
}
/** /**
* Calculate rental cost based on duration and item pricing tiers * Calculate rental cost based on duration and item pricing tiers
* Uses hybrid pricing to find the optimal (cheapest) combination of tiers
*
* @param {Date|string} startDateTime - Rental start date/time * @param {Date|string} startDateTime - Rental start date/time
* @param {Date|string} endDateTime - Rental end date/time * @param {Date|string} endDateTime - Rental end date/time
* @param {Object} item - Item object with pricing information * @param {Object} item - Item object with pricing information
* @returns {number} Total rental cost * @returns {number} Total rental cost
*/ */
static calculateRentalCost(startDateTime, endDateTime, item) { static calculateRentalCost(startDateTime, endDateTime, item) {
const rentalStartDateTime = new Date(startDateTime); const start = new Date(startDateTime);
const rentalEndDateTime = new Date(endDateTime); const end = new Date(endDateTime);
// Calculate rental duration // Calculate total duration in milliseconds
const diffMs = rentalEndDateTime.getTime() - rentalStartDateTime.getTime(); const durationMs = end.getTime() - start.getTime();
const diffHours = Math.ceil(diffMs / (1000 * 60 * 60));
const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24));
const diffWeeks = Math.ceil(diffDays / 7);
// Calculate difference in calendar months if (durationMs <= 0) {
let diffMonths = (rentalEndDateTime.getFullYear() - rentalStartDateTime.getFullYear()) * 12; return 0;
diffMonths += rentalEndDateTime.getMonth() - rentalStartDateTime.getMonth();
// Add 1 if we're past the start day/time in the end month
if (rentalEndDateTime.getDate() > rentalStartDateTime.getDate()) {
diffMonths += 1;
} else if (rentalEndDateTime.getDate() === rentalStartDateTime.getDate() &&
rentalEndDateTime.getTime() > rentalStartDateTime.getTime()) {
diffMonths += 1;
} }
diffMonths = Math.max(1, diffMonths); // Build available pricing tiers
const tiers = this.buildPricingTiers(item);
// Calculate base amount based on duration (tiered pricing) // No pricing tiers = free item
let totalAmount; if (tiers.length === 0) {
return 0;
if (item.pricePerHour && diffHours < 24) {
// Use hourly rate for rentals under 24 hours
totalAmount = diffHours * Number(item.pricePerHour);
} else if (diffDays <= 7 && item.pricePerDay) {
// Use daily rate for rentals <= 7 days
totalAmount = diffDays * Number(item.pricePerDay);
} else if (diffMonths <= 1 && item.pricePerWeek) {
// Use weekly rate for rentals <= 1 calendar month
totalAmount = diffWeeks * Number(item.pricePerWeek);
} else if (diffMonths > 1 && item.pricePerMonth) {
// Use monthly rate for rentals > 1 calendar month
totalAmount = diffMonths * Number(item.pricePerMonth);
} else if (item.pricePerWeek) {
// Fallback to weekly rate if monthly not available
totalAmount = diffWeeks * Number(item.pricePerWeek);
} else if (item.pricePerDay) {
// Fallback to daily rate
totalAmount = diffDays * Number(item.pricePerDay);
} else {
totalAmount = 0;
} }
return totalAmount; // Calculate optimal price using hybrid tier combination
const optimalPrice = this.calculateOptimalForDuration(durationMs, tiers);
return parseFloat(optimalPrice.toFixed(2));
} }
} }

View File

@@ -676,8 +676,7 @@ const ItemDetail: React.FC = () => {
<label className="form-label fw-medium mb-2"> <label className="form-label fw-medium mb-2">
Start Start
</label> </label>
<div className="d-flex gap-2"> <div style={{ width: "60%" }}>
<div style={{ flex: "1 1 50%" }}>
<DatePicker <DatePicker
selected={rentalDates.startDate} selected={rentalDates.startDate}
onChange={(date: Date | null) => onChange={(date: Date | null) =>
@@ -689,13 +688,13 @@ const ItemDetail: React.FC = () => {
minDate={new Date()} minDate={new Date()}
dateFormat="MM/dd/yyyy" dateFormat="MM/dd/yyyy"
placeholderText="mm/dd/yyyy" placeholderText="mm/dd/yyyy"
className="form-control form-control-lg w-100" className="form-control form-control-lg mb-2 w-100"
popperProps={{ strategy: "fixed" }} popperProps={{ strategy: "fixed" }}
/> />
</div> </div>
<div style={{ flex: "1 1 50%" }}>
<select <select
className="form-select form-select-lg" className="form-select form-select-lg"
style={{ width: "60%" }}
value={rentalDates.startTime} value={rentalDates.startTime}
onChange={(e) => onChange={(e) =>
setRentalDates((prev) => ({ setRentalDates((prev) => ({
@@ -705,57 +704,8 @@ const ItemDetail: React.FC = () => {
} }
disabled={!rentalDates.startDate} disabled={!rentalDates.startDate}
> >
<option value="">Pickup</option> <option value="">Pickup Time</option>
{generateTimeOptions( {generateTimeOptions(rentalDates.startDate).map(
rentalDates.startDate
).map((option) => (
<option
key={option.value}
value={option.value}
>
{option.label}
</option>
))}
</select>
</div>
</div>
</div>
<div className="mb-3">
<label className="form-label fw-medium mb-2">
End
</label>
<div className="d-flex gap-2">
<div style={{ flex: "1 1 50%" }}>
<DatePicker
selected={rentalDates.endDate}
onChange={(date: Date | null) =>
setRentalDates((prev) => ({
...prev,
endDate: date,
}))
}
minDate={rentalDates.startDate || new Date()}
dateFormat="MM/dd/yyyy"
placeholderText="mm/dd/yyyy"
className="form-control form-control-lg w-100"
popperProps={{ strategy: "fixed" }}
/>
</div>
<div style={{ flex: "1 1 50%" }}>
<select
className="form-select form-select-lg"
value={rentalDates.endTime}
onChange={(e) =>
setRentalDates((prev) => ({
...prev,
endTime: e.target.value,
}))
}
disabled={!rentalDates.endDate}
>
<option value="">Return</option>
{generateTimeOptions(rentalDates.endDate).map(
(option) => ( (option) => (
<option <option
key={option.value} key={option.value}
@@ -767,7 +717,51 @@ const ItemDetail: React.FC = () => {
)} )}
</select> </select>
</div> </div>
<div className="mb-3">
<label className="form-label fw-medium mb-2">
End
</label>
<div style={{ width: "60%" }}>
<DatePicker
selected={rentalDates.endDate}
onChange={(date: Date | null) =>
setRentalDates((prev) => ({
...prev,
endDate: date,
}))
}
minDate={rentalDates.startDate || new Date()}
dateFormat="MM/dd/yyyy"
placeholderText="mm/dd/yyyy"
className="form-control form-control-lg mb-2 w-100"
popperProps={{ strategy: "fixed" }}
/>
</div> </div>
<select
className="form-select form-select-lg"
style={{ width: "60%" }}
value={rentalDates.endTime}
onChange={(e) =>
setRentalDates((prev) => ({
...prev,
endTime: e.target.value,
}))
}
disabled={!rentalDates.endDate}
>
<option value="">Return Time</option>
{generateTimeOptions(rentalDates.endDate).map(
(option) => (
<option
key={option.value}
value={option.value}
>
{option.label}
</option>
)
)}
</select>
</div> </div>
{rentalDates.startDate && {rentalDates.startDate &&
@@ -802,7 +796,7 @@ const ItemDetail: React.FC = () => {
{!isOwner && item.isAvailable && !isAlreadyRenting && ( {!isOwner && item.isAvailable && !isAlreadyRenting && (
<div className="d-grid"> <div className="d-grid">
<button <button
className="btn btn-primary" className="btn btn-primary btn-lg"
onClick={handleRent} onClick={handleRent}
disabled={ disabled={
!rentalDates.startDate || !rentalDates.startDate ||
@@ -819,7 +813,7 @@ const ItemDetail: React.FC = () => {
{!isOwner && isAlreadyRenting && ( {!isOwner && isAlreadyRenting && (
<div className="d-grid"> <div className="d-grid">
<button <button
className="btn btn-success" className="btn btn-success btn-lg"
disabled disabled
style={{ opacity: 0.8 }} style={{ opacity: 0.8 }}
> >
@@ -928,8 +922,7 @@ const ItemDetail: React.FC = () => {
<label className="form-label fw-medium mb-2"> <label className="form-label fw-medium mb-2">
Start Start
</label> </label>
<div className="d-flex gap-2"> <div style={{ width: "60%" }}>
<div style={{ flex: "1 1 50%" }}>
<DatePicker <DatePicker
selected={rentalDates.startDate} selected={rentalDates.startDate}
onChange={(date: Date | null) => onChange={(date: Date | null) =>
@@ -941,12 +934,12 @@ const ItemDetail: React.FC = () => {
minDate={new Date()} minDate={new Date()}
dateFormat="MM/dd/yyyy" dateFormat="MM/dd/yyyy"
placeholderText="mm/dd/yyyy" placeholderText="mm/dd/yyyy"
className="form-control w-100" className="form-control mb-2 w-100"
/> />
</div> </div>
<div style={{ flex: "1 1 50%" }}>
<select <select
className="form-select" className="form-select"
style={{ width: "60%" }}
value={rentalDates.startTime} value={rentalDates.startTime}
onChange={(e) => onChange={(e) =>
setRentalDates((prev) => ({ setRentalDates((prev) => ({
@@ -956,28 +949,22 @@ const ItemDetail: React.FC = () => {
} }
disabled={!rentalDates.startDate} disabled={!rentalDates.startDate}
> >
<option value="">Pickup</option> <option value="">Pickup Time</option>
{generateTimeOptions(rentalDates.startDate).map( {generateTimeOptions(rentalDates.startDate).map(
(option) => ( (option) => (
<option <option key={option.value} value={option.value}>
key={option.value}
value={option.value}
>
{option.label} {option.label}
</option> </option>
) )
)} )}
</select> </select>
</div> </div>
</div>
</div>
<div className="mb-3"> <div className="mb-3">
<label className="form-label fw-medium mb-2"> <label className="form-label fw-medium mb-2">
End End
</label> </label>
<div className="d-flex gap-2"> <div style={{ width: "60%" }}>
<div style={{ flex: "1 1 50%" }}>
<DatePicker <DatePicker
selected={rentalDates.endDate} selected={rentalDates.endDate}
onChange={(date: Date | null) => onChange={(date: Date | null) =>
@@ -989,12 +976,12 @@ const ItemDetail: React.FC = () => {
minDate={rentalDates.startDate || new Date()} minDate={rentalDates.startDate || new Date()}
dateFormat="MM/dd/yyyy" dateFormat="MM/dd/yyyy"
placeholderText="mm/dd/yyyy" placeholderText="mm/dd/yyyy"
className="form-control w-100" className="form-control mb-2 w-100"
/> />
</div> </div>
<div style={{ flex: "1 1 50%" }}>
<select <select
className="form-select" className="form-select"
style={{ width: "60%" }}
value={rentalDates.endTime} value={rentalDates.endTime}
onChange={(e) => onChange={(e) =>
setRentalDates((prev) => ({ setRentalDates((prev) => ({
@@ -1004,21 +991,16 @@ const ItemDetail: React.FC = () => {
} }
disabled={!rentalDates.endDate} disabled={!rentalDates.endDate}
> >
<option value="">Return</option> <option value="">Return Time</option>
{generateTimeOptions(rentalDates.endDate).map( {generateTimeOptions(rentalDates.endDate).map(
(option) => ( (option) => (
<option <option key={option.value} value={option.value}>
key={option.value}
value={option.value}
>
{option.label} {option.label}
</option> </option>
) )
)} )}
</select> </select>
</div> </div>
</div>
</div>
{rentalDates.startDate && {rentalDates.startDate &&
rentalDates.startTime && rentalDates.startTime &&