Skip to content

Commit a1e89f6

Browse files
committed
more updates
1 parent d093acc commit a1e89f6

File tree

1 file changed

+93
-83
lines changed

1 file changed

+93
-83
lines changed

pcweb/pages/pricing/slider_calculator.py

Lines changed: 93 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,32 @@
1111
from pcweb.constants import REFLEX_CLOUD_URL, PRO_TIERS_TABLE
1212

1313

14-
def format_number(number: int) -> str:
15-
return rx.Var(f"({number}).toLocaleString('en-US')").to(str)
14+
def format_number(number: int | float) -> str:
15+
"""Format number with locale string, handling non-numeric values"""
16+
return rx.Var(
17+
f"(typeof {number} === 'number' ? {number} : 0).toLocaleString('en-US')"
18+
).to(str)
1619

1720

1821
@dataclass
1922
class Machine:
2023
vcpu: int
2124
ram: float
2225
index: int
26+
weekly_credits: float = 0.0
2327

2428
@classmethod
2529
def from_index(cls, index: int) -> "Machine":
2630
"""Create Machine from COMPUTE_TABLE index"""
2731
machine_key = machine_keys[index]
2832
specs = COMPUTE_TABLE[machine_key]
29-
return cls(vcpu=specs["vcpu"], ram=specs["ram"], index=index)
33+
weekly_credits = calculate_weekly_credits(specs["vcpu"], specs["ram"])
34+
return cls(
35+
vcpu=specs["vcpu"],
36+
ram=specs["ram"],
37+
index=index,
38+
weekly_credits=weekly_credits,
39+
)
3040

3141

3242
def calculate_weekly_credits(vcpu: int, ram: float) -> float:
@@ -58,36 +68,92 @@ class MachineState(rx.State):
5868
machines: rx.Field[list[Machine]] = rx.field(default_factory=list)
5969
messages_tier_index: rx.Field[int] = rx.field(default=0)
6070

71+
machines_weekly_credits: rx.Field[float] = rx.field(default=0.0)
72+
current_tier: rx.Field[dict] = rx.field(
73+
default_factory=lambda: {"key": "Pro", "credits": 0, "price": 0}
74+
)
75+
total_credits: rx.Field[str] = rx.field(default="0")
76+
recommended_tier_info: rx.Field[dict] = rx.field(
77+
default_factory=lambda: {
78+
"price": "$0/mo",
79+
"needs_enterprise": False,
80+
"name": "Pro Plan",
81+
"credits": 0,
82+
}
83+
)
84+
85+
def _recalculate_all(self):
86+
"""Recalculate all derived values when state changes"""
87+
# Calculate machines weekly credits using cached values
88+
self.machines_weekly_credits = sum(
89+
machine.weekly_credits for machine in self.machines
90+
)
91+
92+
# Calculate current tier based on message credits
93+
msg_credits = get_message_credits(self.messages_tier_index)
94+
is_enterprise = get_is_enterprise_tier(self.messages_tier_index)
95+
96+
if is_enterprise:
97+
self.current_tier = {
98+
"key": "Enterprise",
99+
"credits": msg_credits,
100+
"price": "custom",
101+
}
102+
else:
103+
tier = self._find_tier_for_credits(msg_credits)
104+
self.current_tier = {
105+
"key": tier["key"] if tier else "Enterprise",
106+
"credits": msg_credits,
107+
"price": tier["price"] if tier else "custom",
108+
}
109+
110+
# Calculate total credits and find tier once
111+
total = msg_credits + round(self.machines_weekly_credits, 2)
112+
total_tier = None if is_enterprise else self._find_tier_for_credits(total)
113+
114+
# Set total credits display
115+
if is_enterprise or not total_tier:
116+
self.total_credits = "Custom"
117+
else:
118+
self.total_credits = f"{total:,}"
119+
120+
# Set recommended tier info
121+
if total_tier:
122+
self.recommended_tier_info = {
123+
"price": f"${total_tier['price']}/mo",
124+
"needs_enterprise": False,
125+
"name": f"{total_tier['key']} Plan",
126+
"credits": total_tier["credits"],
127+
}
128+
else:
129+
self.recommended_tier_info = {
130+
"price": "Custom",
131+
"needs_enterprise": True,
132+
"name": "Enterprise",
133+
"credits": "Custom",
134+
}
135+
61136
@rx.event(temporal=True)
62137
def add_machine(self):
63138
self.machines.append(Machine.from_index(0))
139+
self._recalculate_all()
64140

65141
@rx.event(temporal=True)
66142
def remove_machine(self, index: int):
67143
self.machines = self.machines[:index] + self.machines[index + 1 :]
144+
self._recalculate_all()
68145

69146
@rx.event(temporal=True)
70147
def update_machine(self, index: int, new_machine_index: int):
71148
self.machines[index] = Machine.from_index(new_machine_index)
149+
self._recalculate_all()
72150

73151
@rx.event(temporal=True)
74152
def update_messages_tier(self, new_tier_index: int):
75153
if new_tier_index == self.messages_tier_index:
76154
return
77155
self.messages_tier_index = new_tier_index
78-
79-
def _get_machines_credits(self) -> float:
80-
"""Calculate total weekly credits of all machines"""
81-
return sum(
82-
calculate_weekly_credits(machine.vcpu, machine.ram)
83-
for machine in self.machines
84-
)
85-
86-
def _get_total_credits(self) -> float:
87-
"""Calculate total credits as numeric value"""
88-
return get_message_credits(self.messages_tier_index) + round(
89-
self._get_machines_credits(), 2
90-
)
156+
self._recalculate_all()
91157

92158
def _find_tier_for_credits(self, credits: float) -> dict | None:
93159
"""Find Pro tier that fits the given credits, or None if Enterprise needed"""
@@ -97,63 +163,15 @@ def _find_tier_for_credits(self, credits: float) -> dict | None:
97163
return {"key": tier_key, **tier_data}
98164
return None
99165

100-
@rx.var
101-
def machines_weekly_credits(self) -> float:
102-
"""For UI display of machine credits"""
103-
return self._get_machines_credits()
104-
105-
@rx.var
106-
def current_tier(self) -> dict:
107-
"""Current tier info based on message credits only"""
108-
msg_credits = get_message_credits(self.messages_tier_index)
109-
110-
if get_is_enterprise_tier(self.messages_tier_index):
111-
return {
112-
"key": "Enterprise",
113-
"credits": msg_credits,
114-
"price": "custom",
115-
}
116-
117-
tier = self._find_tier_for_credits(msg_credits)
118-
return {
119-
"key": tier["key"] if tier else "Enterprise",
120-
"credits": msg_credits,
121-
"price": tier["price"] if tier else "custom",
122-
}
123-
124-
@rx.var
125-
def total_credits(self) -> str:
126-
"""Total credits display string"""
127-
total = self._get_total_credits()
128-
if get_is_enterprise_tier(
129-
self.messages_tier_index
130-
) or not self._find_tier_for_credits(total):
131-
return "Custom"
132-
return f"{total:,}"
133-
134-
@rx.var
135-
def recommended_tier_info(self) -> dict:
136-
"""Recommended tier based on total usage"""
137-
tier = self._find_tier_for_credits(self._get_total_credits())
138-
139-
if tier:
140-
return {
141-
"price": f"${tier['price']}/mo",
142-
"needs_enterprise": False,
143-
"name": f"{tier['key']} Plan",
144-
"credits": tier["credits"],
145-
}
146-
147-
return {
148-
"price": "Custom",
149-
"needs_enterprise": True,
150-
"name": "Enterprise",
151-
"credits": "Custom",
152-
}
153-
154-
@rx.event
166+
@rx.event(temporal=True)
155167
def reset_machines(self):
156168
self.reset()
169+
self._recalculate_all()
170+
171+
@rx.event(temporal=True)
172+
def on_load(self):
173+
"""Initialize calculated values on page load"""
174+
self._recalculate_all()
157175

158176

159177
def total_credits_card() -> rx.Component:
@@ -196,9 +214,7 @@ def total_credits_card() -> rx.Component:
196214
class_name="text-secondary-11 text-sm font-medium",
197215
),
198216
rx.el.span(
199-
format_number(
200-
calculate_weekly_credits(machine.vcpu, machine.ram)
201-
),
217+
format_number(machine.weekly_credits),
202218
class_name="text-secondary-12 text-sm font-medium font-mono",
203219
),
204220
class_name="flex flex-row gap-2 items-center justify-between",
@@ -311,13 +327,7 @@ def messages_card() -> rx.Component:
311327
content=rx.cond(
312328
get_is_enterprise_tier(MachineState.messages_tier_index),
313329
"Custom",
314-
rx.cond(
315-
get_is_enterprise_tier(
316-
MachineState.messages_tier_index
317-
),
318-
"Custom Messages",
319-
f"{format_number(MachineState.current_tier['credits'])} Messages",
320-
),
330+
f"{format_number(MachineState.current_tier['credits'])} Messages",
321331
),
322332
open=message_tooltip_open_cs.value,
323333
side="bottom",
@@ -375,7 +385,7 @@ def machine_card(machine: Machine, index: int) -> rx.Component:
375385
),
376386
rx.el.div(
377387
rx.el.span(
378-
f"{calculate_weekly_credits(machine.vcpu, machine.ram)}",
388+
f"{machine.weekly_credits}",
379389
class_name="text-secondary-12 lg:text-lg text-base font-medium font-mono",
380390
),
381391
rx.el.span(
@@ -451,6 +461,6 @@ def slider_calculator() -> rx.Component:
451461
total_credits_card(),
452462
class_name="flex lg:flex-row flex-col lg:gap-10 gap-6 w-full px-6 h-full",
453463
),
454-
on_mount=MachineState.reset_machines,
464+
on_mount=[MachineState.reset_machines, MachineState.on_load],
455465
class_name="flex flex-col w-full max-w-[64.19rem] border-t-0 2xl:border-x divide-y divide-slate-4 2xl:border-b pt-[6rem] justify-center items-center",
456466
)

0 commit comments

Comments
 (0)