finish new demo

This commit is contained in:
Andras Schmelczer 2026-06-26 19:47:23 +01:00
parent e2b85fe819
commit 30d36a33d5
16 changed files with 318 additions and 94 deletions

View file

@ -109,7 +109,6 @@ export default function MapPage({
user,
onLoginClick,
onRegisterClick,
onCheckoutLoginClick,
onCheckoutRegisterClick,
deferTutorial = false,
onSaveSearch,
@ -348,6 +347,7 @@ export default function MapPage({
},
[
activeEntries,
effectiveFilterCap,
fetchAiFilters,
filters,
filtersUnlimited,
@ -358,16 +358,28 @@ export default function MapPage({
);
// Travel-time entries share the non-paying user's filter cap, so block adding one
// when the combined feature + travel count is already at the limit.
// when the combined feature + travel count is already at the limit — and block it
// outright on a shared link, where non-paying users can't add filters at all.
const handleAddTravelTimeEntry = useCallback(
(mode: TransportMode) => {
if (!filtersUnlimited && Object.keys(filters).length + entries.length >= DEMO_MAX_FILTERS) {
if (
!filtersUnlimited &&
(lockFilterAdds || Object.keys(filters).length + entries.length >= effectiveFilterCap)
) {
handleFilterLimitReached();
return;
}
handleAddEntry(mode);
},
[filtersUnlimited, filters, entries, handleAddEntry, handleFilterLimitReached]
[
filtersUnlimited,
lockFilterAdds,
effectiveFilterCap,
filters,
entries,
handleAddEntry,
handleFilterLimitReached,
]
);
const handleClearAll = useCallback(() => {
@ -691,13 +703,17 @@ export default function MapPage({
}, [onDashboardReadyChange]);
// Clear the filter-cap upsell once it's no longer relevant: the user became
// licensed/admin, or dropped back under the cap by removing filters. Prevents a
// stale flag from resurfacing the modal spuriously.
// licensed/admin, or dropped back under the cap by removing filters. On a shared
// link adds are blocked regardless of count, so don't auto-clear there — the user
// dismisses it themselves. Prevents a stale flag from resurfacing spuriously.
useEffect(() => {
if (filtersUnlimited || Object.keys(filters).length < DEMO_MAX_FILTERS) {
if (
filtersUnlimited ||
(!lockFilterAdds && Object.keys(filters).length < effectiveFilterCap)
) {
setFilterLimitHit(false);
}
}, [filtersUnlimited, filters]);
}, [filtersUnlimited, lockFilterAdds, effectiveFilterCap, filters]);
const handleUpgradeClick = useCallback(() => {
onNavigateTo('pricing');
@ -1021,17 +1037,20 @@ export default function MapPage({
</div>
) : null;
// The upgrade modal is shown when a non-paying user hits the filter cap.
// Dismissing it just closes the modal (the filters they have stay applied).
// The upgrade modal is shown when a non-paying user hits the filter cap (or tries
// to add filters on a shared link). Dismissing it just closes the modal (the
// filters they have stay applied). Anonymous users are nudged to register for free
// first (a higher filter allowance + save/share/export); paying is the way to
// unlimited. Registered users see the lifetime upgrade directly.
const showFilterUpgradeModal = filterLimitHit && !filtersUnlimited;
const upgradeModal = showFilterUpgradeModal ? (
<Suspense fallback={null}>
<UpgradeModal
isLoggedIn={!!user}
onLoginClick={() =>
onCheckoutLoginClick ? onCheckoutLoginClick(checkoutReturnPath) : onLoginClick()
}
onRegisterClick={() =>
isLoggedIn={isLoggedIn}
reason={upgradeReason}
onLoginClick={onLoginClick}
onRegisterClick={onRegisterClick}
onRegisterAndUpgrade={() =>
onCheckoutRegisterClick ? onCheckoutRegisterClick(checkoutReturnPath) : onRegisterClick()
}
onStartCheckout={() => license.startCheckout(checkoutReturnPath)}