pricing tiers

This commit is contained in:
jackiettran
2025-11-06 15:54:27 -05:00
parent 9c258177ae
commit 3dca6c803a
14 changed files with 508 additions and 154 deletions

View File

@@ -14,16 +14,28 @@ const ItemCard: React.FC<ItemCardProps> = ({
const isCompact = variant === 'compact';
const getPriceDisplay = () => {
if (item.pricePerDay !== undefined) {
return Number(item.pricePerDay) === 0
? "Free to Borrow"
: `$${Math.floor(Number(item.pricePerDay))}/Day`;
} else if (item.pricePerHour !== undefined) {
return Number(item.pricePerHour) === 0
? "Free to Borrow"
: `$${Math.floor(Number(item.pricePerHour))}/Hour`;
// Collect all available pricing tiers
const pricingTiers: string[] = [];
if (item.pricePerHour && Number(item.pricePerHour) > 0) {
pricingTiers.push(`$${Math.floor(Number(item.pricePerHour))}/hr`);
}
return null;
if (item.pricePerDay && Number(item.pricePerDay) > 0) {
pricingTiers.push(`$${Math.floor(Number(item.pricePerDay))}/day`);
}
if (item.pricePerWeek && Number(item.pricePerWeek) > 0) {
pricingTiers.push(`$${Math.floor(Number(item.pricePerWeek))}/wk`);
}
if (item.pricePerMonth && Number(item.pricePerMonth) > 0) {
pricingTiers.push(`$${Math.floor(Number(item.pricePerMonth))}/mo`);
}
if (pricingTiers.length === 0) {
return "Free to Borrow";
}
// Display up to 2 pricing tiers separated by bullet point
return pricingTiers.slice(0, 2).join(" • ");
};
const getLocationDisplay = () => {

View File

@@ -1,51 +1,105 @@
import React from 'react';
import React from "react";
interface PricingFormProps {
priceType: "hour" | "day";
pricePerHour: number | string;
pricePerDay: number | string;
pricePerWeek: number | string;
pricePerMonth: number | string;
replacementCost: number | string;
minimumRentalDays: number;
onPriceTypeChange: (type: "hour" | "day") => void;
onChange: (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => void;
selectedPricingUnit: string;
showAdvancedPricing: boolean;
enabledTiers: {
hour: boolean;
day: boolean;
week: boolean;
month: boolean;
};
onChange: (
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>
) => void;
onPricingUnitChange: (e: React.ChangeEvent<HTMLSelectElement>) => void;
onToggleAdvancedPricing: () => void;
onTierToggle: (tier: string) => void;
}
const PricingForm: React.FC<PricingFormProps> = ({
priceType,
pricePerHour,
pricePerDay,
pricePerWeek,
pricePerMonth,
replacementCost,
minimumRentalDays,
onPriceTypeChange,
onChange
selectedPricingUnit,
showAdvancedPricing,
enabledTiers,
onChange,
onPricingUnitChange,
onToggleAdvancedPricing,
onTierToggle,
}) => {
// Map pricing unit to field name and label
const pricingUnitMap: Record<
string,
{ field: string; label: string; value: number | string }
> = {
hour: { field: "pricePerHour", label: "Hour", value: pricePerHour },
day: { field: "pricePerDay", label: "Day", value: pricePerDay },
week: { field: "pricePerWeek", label: "Week", value: pricePerWeek },
month: { field: "pricePerMonth", label: "Month", value: pricePerMonth },
};
// When advanced pricing is on, show ALL 4 options
// When advanced pricing is off, show only the 3 non-selected options
const advancedPricingOptions = showAdvancedPricing
? Object.entries(pricingUnitMap)
: Object.entries(pricingUnitMap).filter(
([key]) => key !== selectedPricingUnit
);
const selectedUnit = pricingUnitMap[selectedPricingUnit];
return (
<div className="card mb-4">
<div className="card-body">
<div className="mb-3">
<div className="row align-items-center">
<div className="col-auto">
<label className="col-form-label">Price per</label>
</div>
<div className="col-auto">
<h5 className="card-title">Pricing</h5>
<p className="text-muted small mb-3">
{showAdvancedPricing
? "Set multiple pricing tiers for flexible rental rates."
: "Set your primary pricing rate, or use Advanced Pricing for multiple tiers."}
</p>
{/* Pricing Unit Dropdown - Only show when advanced pricing is OFF */}
{!showAdvancedPricing && (
<>
<div className="mb-3">
<label htmlFor="pricingUnit" className="form-label">
Pricing Unit
</label>
<select
className="form-select"
value={priceType}
onChange={(e) => onPriceTypeChange(e.target.value as "hour" | "day")}
id="pricingUnit"
value={selectedPricingUnit}
onChange={onPricingUnitChange}
>
<option value="hour">Hour</option>
<option value="day">Day</option>
<option value="week">Week</option>
<option value="month">Month</option>
</select>
</div>
<div className="col">
{/* Primary Price Input */}
<div className="mb-3">
<label htmlFor={selectedUnit.field} className="form-label mb-0">
Price per {selectedUnit.label}
</label>
<div className="input-group">
<span className="input-group-text">$</span>
<input
type="number"
className="form-control"
id={priceType === "hour" ? "pricePerHour" : "pricePerDay"}
name={priceType === "hour" ? "pricePerHour" : "pricePerDay"}
value={priceType === "hour" ? pricePerHour : pricePerDay}
id={selectedUnit.field}
name={selectedUnit.field}
value={selectedUnit.value}
onChange={onChange}
step="0.01"
min="0"
@@ -53,24 +107,63 @@ const PricingForm: React.FC<PricingFormProps> = ({
/>
</div>
</div>
</div>
</div>
</>
)}
{/* Advanced Pricing Toggle */}
<div className="mb-3">
<label htmlFor="minimumRentalDays" className="form-label">
Minimum Rental {priceType === "hour" ? "Hours" : "Days"}
</label>
<input
type="number"
className="form-control"
id="minimumRentalDays"
name="minimumRentalDays"
value={minimumRentalDays}
onChange={onChange}
min="1"
/>
<button
type="button"
className="btn btn-link p-0 text-decoration-none"
onClick={onToggleAdvancedPricing}
>
{showAdvancedPricing ? "▼" : "▶"} Advanced Pricing
</button>
</div>
{/* Advanced Pricing Section */}
{showAdvancedPricing && (
<div className="border rounded p-3 mb-3 bg-light">
<p className="text-muted small mb-3">
Set multiple pricing tiers. Check the boxes for the tiers you want to use.
</p>
{advancedPricingOptions.map(([key, { field, label, value }]) => (
<div className="mb-3" key={key}>
<div className="form-check mb-2">
<input
className="form-check-input"
type="checkbox"
id={`enable-${key}`}
checked={enabledTiers[key as keyof typeof enabledTiers]}
onChange={() => onTierToggle(key)}
/>
<label className="form-check-label" htmlFor={`enable-${key}`}>
Price per {label}
</label>
</div>
<div className="input-group">
<span className="input-group-text">$</span>
<input
type="number"
className="form-control"
id={field}
name={field}
value={value}
onChange={onChange}
step="0.01"
min="0"
placeholder="0.00"
disabled={!enabledTiers[key as keyof typeof enabledTiers]}
/>
</div>
</div>
))}
</div>
)}
<hr className="my-4" />
{/* Replacement Cost */}
<div className="mb-3">
<label htmlFor="replacementCost" className="form-label mb-0">
Replacement Cost *
@@ -99,4 +192,4 @@ const PricingForm: React.FC<PricingFormProps> = ({
);
};
export default PricingForm;
export default PricingForm;