pricing tiers
This commit is contained in:
@@ -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 = () => {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user