Skip to content

Commit 1ebd75e

Browse files
Fix VariablePricingModal.tsx based on code review feedback
1 parent 9288b83 commit 1ebd75e

1 file changed

Lines changed: 74 additions & 46 deletions

File tree

apps/web/components/eventtype/VariablePricingModal.tsx

Lines changed: 74 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
Switch,
1818
TextField,
1919
showToast,
20+
Spinner,
2021
} from "@calcom/ui";
2122
import { Plus, Edit2, Trash2 } from "@calcom/ui/components/icon";
2223

@@ -33,49 +34,49 @@ type FormData = {
3334
};
3435

3536
const PRICE_MODIFIER_ACTIONS = [
36-
{ value: "add", label: "Add (Fixed Amount)" },
37-
{ value: "subtract", label: "Subtract (Fixed Amount)" },
38-
{ value: "multiply", label: "Multiply (Percentage)" },
39-
{ value: "divide", label: "Divide (Percentage)" },
40-
{ value: "set", label: "Set Fixed Price" },
37+
{ value: "add", label: t("add_fixed_amount") },
38+
{ value: "subtract", label: t("subtract_fixed_amount") },
39+
{ value: "multiply", label: t("multiply_percentage") },
40+
{ value: "divide", label: t("divide_percentage") },
41+
{ value: "set", label: t("set_fixed_price") },
4142
];
4243

4344
const CONDITION_TYPES = [
44-
{ value: "duration", label: "Duration" },
45-
{ value: "timeOfDay", label: "Time of Day" },
46-
{ value: "dayOfWeek", label: "Day of Week" },
47-
{ value: "custom", label: "Custom Field" },
45+
{ value: "duration", label: t("duration") },
46+
{ value: "timeOfDay", label: t("time_of_day") },
47+
{ value: "dayOfWeek", label: t("day_of_week") },
48+
{ value: "custom", label: t("custom_field") },
4849
];
4950

5051
const COMPARISON_OPERATORS = [
51-
{ value: "eq", label: "Equals" },
52-
{ value: "neq", label: "Not Equals" },
53-
{ value: "gt", label: "Greater Than" },
54-
{ value: "gte", label: "Greater Than or Equal" },
55-
{ value: "lt", label: "Less Than" },
56-
{ value: "lte", label: "Less Than or Equal" },
57-
{ value: "contains", label: "Contains" },
58-
{ value: "custom", label: "Custom Function" },
52+
{ value: "eq", label: t("equals") },
53+
{ value: "neq", label: t("not_equals") },
54+
{ value: "gt", label: t("greater_than") },
55+
{ value: "gte", label: t("greater_than_or_equal") },
56+
{ value: "lt", label: t("less_than") },
57+
{ value: "lte", label: t("less_than_or_equal") },
58+
{ value: "contains", label: t("contains") },
59+
{ value: "custom", label: t("custom_function") },
5960
];
6061

6162
const DAYS_OF_WEEK = [
62-
{ value: "sunday", label: "Sunday" },
63-
{ value: "monday", label: "Monday" },
64-
{ value: "tuesday", label: "Tuesday" },
65-
{ value: "wednesday", label: "Wednesday" },
66-
{ value: "thursday", label: "Thursday" },
67-
{ value: "friday", label: "Friday" },
68-
{ value: "saturday", label: "Saturday" },
63+
{ value: "sunday", label: t("sunday") },
64+
{ value: "monday", label: t("monday") },
65+
{ value: "tuesday", label: t("tuesday") },
66+
{ value: "wednesday", label: t("wednesday") },
67+
{ value: "thursday", label: t("thursday") },
68+
{ value: "friday", label: t("friday") },
69+
{ value: "saturday", label: t("saturday") },
6970
];
7071

7172
const CURRENCIES = [
72-
{ value: "USD", label: "USD ($)" },
73-
{ value: "EUR", label: "EUR (€)" },
74-
{ value: "GBP", label: "GBP (£)" },
75-
{ value: "CAD", label: "CAD ($)" },
76-
{ value: "AUD", label: "AUD ($)" },
77-
{ value: "JPY", label: "JPY (¥)" },
78-
{ value: "INR", label: "INR (₹)" },
73+
{ value: "USD", label: t("currency_usd") },
74+
{ value: "EUR", label: t("currency_eur") },
75+
{ value: "GBP", label: t("currency_gbp") },
76+
{ value: "CAD", label: t("currency_cad") },
77+
{ value: "AUD", label: t("currency_aud") },
78+
{ value: "JPY", label: t("currency_jpy") },
79+
{ value: "INR", label: t("currency_inr") },
7980
];
8081

8182
export function VariablePricingModal({ eventTypeId, onClose }: VariablePricingProps) {
@@ -105,7 +106,7 @@ export function VariablePricingModal({ eventTypeId, onClose }: VariablePricingPr
105106
const config = pricingData.pricingConfig;
106107
form.setValue("variablePricing.enabled", config.enabled);
107108
form.setValue("variablePricing.basePrice", config.basePrice / 100); // Convert cents to dollars
108-
form.setValue("variablePricing.currency", config.currency);
109+
form.setValue("variablePricing.currency", config.currency?.toUpperCase?.() || "USD");
109110
form.setValue("variablePricing.rules", config.rules);
110111
}
111112
}, [pricingData, form]);
@@ -121,15 +122,30 @@ export function VariablePricingModal({ eventTypeId, onClose }: VariablePricingPr
121122
enabled: data.enabled,
122123
basePrice,
123124
currency: data.currency,
124-
rules: data.rules.map((rule) => ({
125-
id: rule.id,
126-
type: rule.type,
127-
enabled: rule.enabled,
128-
description: rule.description,
129-
action: rule.action,
130-
amount: rule.amount,
131-
condition: rule.condition,
132-
})),
125+
rules: data.rules.map((rule) => {
126+
return {
127+
id: rule.id,
128+
type: rule.type,
129+
enabled: rule.enabled,
130+
description: rule.description,
131+
priority: rule.priority ?? 0,
132+
condition: rule.condition,
133+
// map UI fields to pricing model
134+
...(rule.price != null
135+
? { price: Math.round(rule.price) } // already cents if editing existing
136+
: rule.action === "set"
137+
? { price: Math.round((rule.amount || 0) * 100) }
138+
: rule.action === "add"
139+
? { priceModifier: { type: "surcharge", value: Math.round((rule.amount || 0) * 100) } }
140+
: rule.action === "subtract"
141+
? { priceModifier: { type: "discount", value: Math.round((rule.amount || 0) * 100) } }
142+
: rule.action === "multiply"
143+
? { priceModifier: { type: "surcharge", value: 0, percentage: rule.amount || 0 } }
144+
: rule.action === "divide"
145+
? { priceModifier: { type: "discount", value: 0, percentage: rule.amount || 0 } }
146+
: {}),
147+
};
148+
}),
133149
},
134150
});
135151
};
@@ -164,7 +180,7 @@ export function VariablePricingModal({ eventTypeId, onClose }: VariablePricingPr
164180

165181
{isLoading ? (
166182
<div className="flex justify-center py-8">
167-
<div className="spinner">Loading...</div>
183+
<Spinner />
168184
</div>
169185
) : (
170186
<>
@@ -356,8 +372,11 @@ function AddRuleDialog({ onClose, onAddRule, initialRule }: AddRuleDialogProps)
356372
const [ruleType, setRuleType] = useState<PricingRule["type"]>(initialRule?.type || "duration");
357373
const [enabled, setEnabled] = useState(initialRule?.enabled ?? true);
358374
const [description, setDescription] = useState(initialRule?.description || "");
359-
const [action, setAction] = useState(initialRule?.action || "add");
360-
const [amount, setAmount] = useState(initialRule?.amount || 0);
375+
const [action, setAction] = useState<"add" | "subtract" | "multiply" | "divide" | "set">(
376+
// @ts-expect-error UI-only state
377+
initialRule?.price ? "set" : "add"
378+
);
379+
const [amount, setAmount] = useState<number>(0);
361380

362381
// Duration condition fields
363382
const [minDuration, setMinDuration] = useState(
@@ -435,9 +454,18 @@ function AddRuleDialog({ onClose, onAddRule, initialRule }: AddRuleDialogProps)
435454
type: ruleType,
436455
enabled,
437456
description,
438-
action: action as PricingRule["action"],
439-
amount: parseInt(amount.toString()),
440457
condition,
458+
...(action === "set"
459+
? { price: Math.round(amount * 100) }
460+
: action === "add"
461+
? { priceModifier: { type: "surcharge", value: Math.round(amount * 100) } }
462+
: action === "subtract"
463+
? { priceModifier: { type: "discount", value: Math.round(amount * 100) } }
464+
: action === "multiply"
465+
? { priceModifier: { type: "surcharge", value: 0, percentage: amount } }
466+
: action === "divide"
467+
? { priceModifier: { type: "discount", value: 0, percentage: amount } }
468+
: {}),
441469
};
442470

443471
onAddRule(rule);

0 commit comments

Comments
 (0)