lots of fixes

This commit is contained in:
Ayush Rodrigues
2026-01-18 23:37:27 +00:00
parent 464575f223
commit de180fa437
35 changed files with 828 additions and 438 deletions

203
.cursor/debug.log Normal file
View File

@@ -0,0 +1,203 @@
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":true,"isVersionChanged":true,"isProductUpdated":true,"productId":"free_plan","productVersion":1,"willUpdate":true},"timestamp":1768767206353,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:setBaseProduct","message":"updating baseProduct","data":{"frontendProductItemsCount":1,"frontendProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38IUPp9xbsN9aTLxJWylhmhpSMd"}]},"timestamp":1768767206353,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":false,"productId":"free_plan","productVersion":1,"lastProductId":"free_plan","lastProductVersion":1,"willUpdate":false},"timestamp":1768767206354,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":false,"productId":"free_plan","productVersion":1,"lastProductId":"free_plan","lastProductVersion":1,"willUpdate":false},"timestamp":1768767206365,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38IUPp9xbsN9aTLxJWylhmhpSMd"}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38IUPp9xbsN9aTLxJWylhmhpSMd"}]},"timestamp":1768767206361,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38IUPp9xbsN9aTLxJWylhmhpSMd"}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38IUPp9xbsN9aTLxJWylhmhpSMd"}]},"timestamp":1768767206361,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":true,"productId":"free_plan","productVersion":1,"lastProductId":"free_plan","lastProductVersion":1,"willUpdate":true},"timestamp":1768767207732,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:setBaseProduct","message":"updating baseProduct","data":{"frontendProductItemsCount":1,"frontendProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38IUPp9xbsN9aTLxJWylhmhpSMd"}]},"timestamp":1768767207732,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38IUPp9xbsN9aTLxJWylhmhpSMd"}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38IUPp9xbsN9aTLxJWylhmhpSMd"}]},"timestamp":1768767207732,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38IUPp9xbsN9aTLxJWylhmhpSMd"}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38IUPp9xbsN9aTLxJWylhmhpSMd"}]},"timestamp":1768767207733,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"analytics","item1Interval":null,"item1IncludedUsage":null,"items2Count":1,"items2FeatureIds":["messages"]},"timestamp":1768767208701,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38IUPp9xbsN9aTLxJWylhmhpSMd"},{"feature_id":"analytics","interval":null,"included_usage":null,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38IUPp9xbsN9aTLxJWylhmhpSMd"}]},"timestamp":1768767208701,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"analytics","item1Interval":null,"item1IncludedUsage":null,"items2Count":1,"items2FeatureIds":["messages"]},"timestamp":1768767208701,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"analytics","item1Interval":null,"item1IncludedUsage":null,"items2Count":1,"items2FeatureIds":["messages"]},"timestamp":1768767208701,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38IUPp9xbsN9aTLxJWylhmhpSMd"},{"feature_id":"analytics","interval":null,"included_usage":null,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38IUPp9xbsN9aTLxJWylhmhpSMd"}]},"timestamp":1768767208701,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"analytics","item1Interval":null,"item1IncludedUsage":null,"items2Count":1,"items2FeatureIds":["messages"]},"timestamp":1768767208702,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":false,"productId":"free_plan","productVersion":1,"lastProductId":"free_plan","lastProductVersion":1,"willUpdate":false},"timestamp":1768767208711,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"SaveChangesBar.tsx:handleSaveClicked:start","message":"save clicked - before save","data":{"productId":"free_plan","itemsCount":2,"items":[{"feature_id":"messages","interval":null,"included_usage":10},{"feature_id":"analytics","interval":null,"included_usage":null}]},"timestamp":1768767210156,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"analytics","item1Interval":null,"item1IncludedUsage":null,"items2Count":1,"items2FeatureIds":["messages"]},"timestamp":1768767217153,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":true,"isProductUpdated":true,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":1,"willUpdate":true},"timestamp":1768767220542,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:setBaseProduct","message":"updating baseProduct","data":{"frontendProductItemsCount":2,"frontendProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","entitlement_id":"ent_38RfHfo63jeH40j8nB7K1BAHLeT"}]},"timestamp":1768767220542,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","entitlement_id":"ent_38RfHfo63jeH40j8nB7K1BAHLeT"}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","entitlement_id":"ent_38RfHfo63jeH40j8nB7K1BAHLeT"}]},"timestamp":1768767220548,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","entitlement_id":"ent_38RfHfo63jeH40j8nB7K1BAHLeT"}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","entitlement_id":"ent_38RfHfo63jeH40j8nB7K1BAHLeT"}]},"timestamp":1768767220548,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":false,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":2,"willUpdate":false},"timestamp":1768767220550,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","entitlement_id":"ent_38RfHfo63jeH40j8nB7K1BAHLeT"}]},"timestamp":1768767226001,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","entitlement_id":"ent_38RfHfo63jeH40j8nB7K1BAHLeT"}]},"timestamp":1768767226002,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":false,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":2,"willUpdate":false},"timestamp":1768767226003,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"SaveChangesBar.tsx:handleSaveClicked:start","message":"save clicked - before save","data":{"productId":"free_plan","itemsCount":1,"items":[{"feature_id":"messages","interval":null,"included_usage":10}]},"timestamp":1768767226796,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"SaveChangesBar.tsx:onSuccess","message":"save onSuccess - about to refetch","data":{},"timestamp":1768767232230,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":true,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":2,"willUpdate":true},"timestamp":1768767233610,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:setBaseProduct","message":"updating baseProduct","data":{"frontendProductItemsCount":1,"frontendProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767233610,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767233611,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767233611,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"SaveChangesBar.tsx:onSuccess:afterRefetch","message":"refetch completed","data":{},"timestamp":1768767235270,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"SaveChangesBar.tsx:handleSaveClicked:end","message":"save completed","data":{"result":true},"timestamp":1768767235270,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"analytics","item1Interval":null,"item1IncludedUsage":null,"items2Count":1,"items2FeatureIds":["messages"]},"timestamp":1768767236608,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","interval":null,"included_usage":null,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767236608,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"analytics","item1Interval":null,"item1IncludedUsage":null,"items2Count":1,"items2FeatureIds":["messages"]},"timestamp":1768767236608,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"analytics","item1Interval":null,"item1IncludedUsage":null,"items2Count":1,"items2FeatureIds":["messages"]},"timestamp":1768767236608,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","interval":null,"included_usage":null,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767236608,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"analytics","item1Interval":null,"item1IncludedUsage":null,"items2Count":1,"items2FeatureIds":["messages"]},"timestamp":1768767236609,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":false,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":2,"willUpdate":false},"timestamp":1768767236614,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"SaveChangesBar.tsx:handleSaveClicked:start","message":"save clicked - before save","data":{"productId":"free_plan","itemsCount":2,"items":[{"feature_id":"messages","interval":null,"included_usage":10},{"feature_id":"analytics","interval":null,"included_usage":null}]},"timestamp":1768767237868,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"SaveChangesBar.tsx:onSuccess","message":"save onSuccess - about to refetch","data":{},"timestamp":1768767242801,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":true,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":2,"willUpdate":true},"timestamp":1768767244180,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:setBaseProduct","message":"updating baseProduct","data":{"frontendProductItemsCount":2,"frontendProductItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfKZrFZYfWslXTJOSbeoBjzkV"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767244181,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","interval":null,"included_usage":null,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfKZrFZYfWslXTJOSbeoBjzkV"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767244181,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"compareItemUtils.ts:featureItemsAreSame","message":"feature items comparison failed","data":{"featureId":"analytics","failedChecks":[{"check":"reset_usage_when_enabled","message":"Reset usage when enabled different: true !== false"}],"item1ResetUsage":true,"item2ResetUsage":false,"item1Interval":null,"item1IncludedUsage":null},"timestamp":1768767244181,"sessionId":"debug-session","hypothesisId":"H3"}
{"location":"compareItemUtils.ts:featureItemsAreSame","message":"feature items comparison failed","data":{"featureId":"analytics","failedChecks":[{"check":"reset_usage_when_enabled","message":"Reset usage when enabled different: true !== false"}],"item1ResetUsage":true,"item2ResetUsage":false,"item1Interval":null,"item1IncludedUsage":null},"timestamp":1768767244181,"sessionId":"debug-session","hypothesisId":"H3"}
{"location":"compareProductUtils.ts:productsAreSame:itemsDifferent","message":"items not same after comparison","data":{"item1":"{\"feature_id\":\"analytics\",\"feature_type\":\"static\",\"included_usage\":null,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":true,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","item2":"{\"feature_id\":\"analytics\",\"entity_feature_id\":null,\"entitlement_id\":\"ent_38RfKZrFZYfWslXTJOSbeoBjzkV\",\"feature_type\":\"static\",\"reset_usage_when_enabled\":false,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","featureId":"analytics"},"timestamp":1768767244181,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:itemsDifferent","message":"items not same after comparison","data":{"item1":"{\"feature_id\":\"analytics\",\"feature_type\":\"static\",\"included_usage\":null,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":true,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","item2":"{\"feature_id\":\"analytics\",\"entity_feature_id\":null,\"entitlement_id\":\"ent_38RfKZrFZYfWslXTJOSbeoBjzkV\",\"feature_type\":\"static\",\"reset_usage_when_enabled\":false,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","featureId":"analytics"},"timestamp":1768767244182,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareItemUtils.ts:featureItemsAreSame","message":"feature items comparison failed","data":{"featureId":"analytics","failedChecks":[{"check":"reset_usage_when_enabled","message":"Reset usage when enabled different: true !== false"}],"item1ResetUsage":true,"item2ResetUsage":false,"item1Interval":null,"item1IncludedUsage":null},"timestamp":1768767244182,"sessionId":"debug-session","hypothesisId":"H3"}
{"location":"compareProductUtils.ts:productsAreSame:itemsDifferent","message":"items not same after comparison","data":{"item1":"{\"feature_id\":\"analytics\",\"feature_type\":\"static\",\"included_usage\":null,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":true,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","item2":"{\"feature_id\":\"analytics\",\"entity_feature_id\":null,\"entitlement_id\":\"ent_38RfKZrFZYfWslXTJOSbeoBjzkV\",\"feature_type\":\"static\",\"reset_usage_when_enabled\":false,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","featureId":"analytics"},"timestamp":1768767244182,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","interval":null,"included_usage":null,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfKZrFZYfWslXTJOSbeoBjzkV"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767244182,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"compareItemUtils.ts:featureItemsAreSame","message":"feature items comparison failed","data":{"featureId":"analytics","failedChecks":[{"check":"reset_usage_when_enabled","message":"Reset usage when enabled different: true !== false"}],"item1ResetUsage":true,"item2ResetUsage":false,"item1Interval":null,"item1IncludedUsage":null},"timestamp":1768767244182,"sessionId":"debug-session","hypothesisId":"H3"}
{"location":"compareProductUtils.ts:productsAreSame:itemsDifferent","message":"items not same after comparison","data":{"item1":"{\"feature_id\":\"analytics\",\"feature_type\":\"static\",\"included_usage\":null,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":true,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","item2":"{\"feature_id\":\"analytics\",\"entity_feature_id\":null,\"entitlement_id\":\"ent_38RfKZrFZYfWslXTJOSbeoBjzkV\",\"feature_type\":\"static\",\"reset_usage_when_enabled\":false,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","featureId":"analytics"},"timestamp":1768767244182,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"SaveChangesBar.tsx:onSuccess:afterRefetch","message":"refetch completed","data":{},"timestamp":1768767245839,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"SaveChangesBar.tsx:handleSaveClicked:end","message":"save completed","data":{"result":true},"timestamp":1768767245839,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"compareItemUtils.ts:featureItemsAreSame","message":"feature items comparison failed","data":{"featureId":"analytics","failedChecks":[{"check":"reset_usage_when_enabled","message":"Reset usage when enabled different: true !== false"}],"item1ResetUsage":true,"item2ResetUsage":false,"item1Interval":null,"item1IncludedUsage":null},"timestamp":1768767394297,"sessionId":"debug-session","hypothesisId":"H3"}
{"location":"compareItemUtils.ts:featureItemsAreSame","message":"feature items comparison failed","data":{"featureId":"analytics","failedChecks":[{"check":"reset_usage_when_enabled","message":"Reset usage when enabled different: true !== false"}],"item1ResetUsage":true,"item2ResetUsage":false,"item1Interval":null,"item1IncludedUsage":null},"timestamp":1768767394298,"sessionId":"debug-session","hypothesisId":"H3"}
{"location":"compareProductUtils.ts:productsAreSame:itemsDifferent","message":"items not same after comparison","data":{"item1":"{\"feature_id\":\"analytics\",\"feature_type\":\"static\",\"included_usage\":null,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":true,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","item2":"{\"feature_id\":\"analytics\",\"entity_feature_id\":null,\"entitlement_id\":\"ent_38RfKZrFZYfWslXTJOSbeoBjzkV\",\"feature_type\":\"static\",\"reset_usage_when_enabled\":false,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","featureId":"analytics"},"timestamp":1768767394297,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:itemsDifferent","message":"items not same after comparison","data":{"item1":"{\"feature_id\":\"analytics\",\"feature_type\":\"static\",\"included_usage\":null,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":true,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","item2":"{\"feature_id\":\"analytics\",\"entity_feature_id\":null,\"entitlement_id\":\"ent_38RfKZrFZYfWslXTJOSbeoBjzkV\",\"feature_type\":\"static\",\"reset_usage_when_enabled\":false,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","featureId":"analytics"},"timestamp":1768767394298,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","interval":null,"included_usage":null,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfKZrFZYfWslXTJOSbeoBjzkV"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767394297,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","interval":null,"included_usage":null,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfKZrFZYfWslXTJOSbeoBjzkV"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767394298,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"compareItemUtils.ts:featureItemsAreSame","message":"feature items comparison failed","data":{"featureId":"analytics","failedChecks":[{"check":"reset_usage_when_enabled","message":"Reset usage when enabled different: true !== false"}],"item1ResetUsage":true,"item2ResetUsage":false,"item1Interval":null,"item1IncludedUsage":null},"timestamp":1768767394298,"sessionId":"debug-session","hypothesisId":"H3"}
{"location":"compareProductUtils.ts:productsAreSame:itemsDifferent","message":"items not same after comparison","data":{"item1":"{\"feature_id\":\"analytics\",\"feature_type\":\"static\",\"included_usage\":null,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":true,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","item2":"{\"feature_id\":\"analytics\",\"entity_feature_id\":null,\"entitlement_id\":\"ent_38RfKZrFZYfWslXTJOSbeoBjzkV\",\"feature_type\":\"static\",\"reset_usage_when_enabled\":false,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","featureId":"analytics"},"timestamp":1768767394298,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareItemUtils.ts:featureItemsAreSame","message":"feature items comparison failed","data":{"featureId":"analytics","failedChecks":[{"check":"reset_usage_when_enabled","message":"Reset usage when enabled different: true !== false"}],"item1ResetUsage":true,"item2ResetUsage":false,"item1Interval":null,"item1IncludedUsage":null},"timestamp":1768767394297,"sessionId":"debug-session","hypothesisId":"H3"}
{"location":"compareProductUtils.ts:productsAreSame:itemsDifferent","message":"items not same after comparison","data":{"item1":"{\"feature_id\":\"analytics\",\"feature_type\":\"static\",\"included_usage\":null,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":true,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","item2":"{\"feature_id\":\"analytics\",\"entity_feature_id\":null,\"entitlement_id\":\"ent_38RfKZrFZYfWslXTJOSbeoBjzkV\",\"feature_type\":\"static\",\"reset_usage_when_enabled\":false,\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","featureId":"analytics"},"timestamp":1768767394297,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":true,"isVersionChanged":true,"isProductUpdated":true,"productId":"free_plan","productVersion":2,"willUpdate":true},"timestamp":1768767394313,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:setBaseProduct","message":"updating baseProduct","data":{"frontendProductItemsCount":2,"frontendProductItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfKZrFZYfWslXTJOSbeoBjzkV"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767394314,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":false,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":2,"willUpdate":false},"timestamp":1768767394318,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfKZrFZYfWslXTJOSbeoBjzkV"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}],"baseProductItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfKZrFZYfWslXTJOSbeoBjzkV"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767394332,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfKZrFZYfWslXTJOSbeoBjzkV"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}],"baseProductItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfKZrFZYfWslXTJOSbeoBjzkV"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767394332,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":false,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":2,"willUpdate":false},"timestamp":1768767394337,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}],"baseProductItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfKZrFZYfWslXTJOSbeoBjzkV"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767501092,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}],"baseProductItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfKZrFZYfWslXTJOSbeoBjzkV"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767501092,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":false,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":2,"willUpdate":false},"timestamp":1768767501096,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"SaveChangesBar.tsx:handleSaveClicked:start","message":"save clicked - before save","data":{"productId":"free_plan","itemsCount":1,"items":[{"feature_id":"messages","interval":null,"included_usage":10}]},"timestamp":1768767501888,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"SaveChangesBar.tsx:onSuccess","message":"save onSuccess - about to refetch","data":{},"timestamp":1768767508153,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":true,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":2,"willUpdate":true},"timestamp":1768767509550,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:setBaseProduct","message":"updating baseProduct","data":{"frontendProductItemsCount":1,"frontendProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767509550,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767509550,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767509551,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"SaveChangesBar.tsx:onSuccess:afterRefetch","message":"refetch completed","data":{},"timestamp":1768767511210,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"SaveChangesBar.tsx:handleSaveClicked:end","message":"save completed","data":{"result":true},"timestamp":1768767511210,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","interval":null,"included_usage":null}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767525751,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"analytics","item1Interval":null,"item1IncludedUsage":null,"items2Count":1,"items2FeatureIds":["messages"]},"timestamp":1768767525751,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"analytics","item1Interval":null,"item1IncludedUsage":null,"items2Count":1,"items2FeatureIds":["messages"]},"timestamp":1768767525751,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"analytics","item1Interval":null,"item1IncludedUsage":null,"items2Count":1,"items2FeatureIds":["messages"]},"timestamp":1768767525751,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"analytics","item1Interval":null,"item1IncludedUsage":null,"items2Count":1,"items2FeatureIds":["messages"]},"timestamp":1768767525751,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","interval":null,"included_usage":null}],"baseProductItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767525751,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":false,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":2,"willUpdate":false},"timestamp":1768767525757,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"SaveChangesBar.tsx:handleSaveClicked:start","message":"save clicked - before save","data":{"productId":"free_plan","itemsCount":2,"items":[{"feature_id":"messages","interval":null,"included_usage":10},{"feature_id":"analytics","interval":null,"included_usage":null}]},"timestamp":1768767526804,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"SaveChangesBar.tsx:onSuccess","message":"save onSuccess - about to refetch","data":{},"timestamp":1768767531740,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":true,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":2,"willUpdate":true},"timestamp":1768767533130,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:setBaseProduct","message":"updating baseProduct","data":{"frontendProductItemsCount":2,"frontendProductItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfuuS2oOJiQBLwQrlKxo8TOM4"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767533131,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","interval":null,"included_usage":null}],"baseProductItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfuuS2oOJiQBLwQrlKxo8TOM4"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767533131,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"},{"feature_id":"analytics","interval":null,"included_usage":null}],"baseProductItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfuuS2oOJiQBLwQrlKxo8TOM4"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767533131,"sessionId":"debug-session","hypothesisId":"H1-H3"}
{"location":"SaveChangesBar.tsx:onSuccess:afterRefetch","message":"refetch completed","data":{},"timestamp":1768767534789,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"SaveChangesBar.tsx:handleSaveClicked:end","message":"save completed","data":{"result":true},"timestamp":1768767534789,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":false,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":2,"willUpdate":false},"timestamp":1768767554592,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":true,"isVersionChanged":true,"isProductUpdated":true,"productId":"free_plan","productVersion":2,"willUpdate":true},"timestamp":1768767559098,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:setBaseProduct","message":"updating baseProduct","data":{"frontendProductItemsCount":2,"frontendProductItems":[{"feature_id":"analytics","entitlement_id":"ent_38RfuuS2oOJiQBLwQrlKxo8TOM4"},{"feature_id":"messages","interval":null,"included_usage":10,"reset_usage_when_enabled":true,"entitlement_id":"ent_38RfHdX9I9BqCWnytV2ylYvGgnu"}]},"timestamp":1768767559098,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":false,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":2,"willUpdate":false},"timestamp":1768767559099,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"useProductSync.ts:useEffect","message":"sync effect triggered","data":{"isNewProduct":false,"isVersionChanged":false,"isProductUpdated":false,"productId":"free_plan","productVersion":2,"lastProductId":"free_plan","lastProductVersion":2,"willUpdate":false},"timestamp":1768767559112,"sessionId":"debug-session","hypothesisId":"H4"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":null,"item1IncludedUsage":null,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767564109,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":null,"item1IncludedUsage":null,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767564109,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":null,"item1IncludedUsage":null,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767564109,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":null,"item1IncludedUsage":null,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767564109,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":null,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767568548,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":null,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767568548,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":null,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767568548,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":null,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767568548,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":2,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767569476,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":2,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767569476,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":2,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767569476,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":2,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767569476,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":25,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767569717,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":25,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767569717,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":25,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767569717,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":25,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767569717,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"SaveChangesBar.tsx:handleSaveClicked:start","message":"save clicked - before save","data":{"productId":"free_plan","itemsCount":3,"items":[{"feature_id":"analytics"},{"feature_id":"messages","interval":null,"included_usage":10},{"feature_id":"seats","interval":"month","included_usage":25}]},"timestamp":1768767573201,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":25,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767573208,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":25,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767573209,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":25,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767573209,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":25,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767573209,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"SaveChangesBar.tsx:handleSaveClicked:end","message":"save completed","data":{"result":false},"timestamp":1768767574954,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":25,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767575485,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":25,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767575485,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":25,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767575485,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"compareProductUtils.ts:productsAreSame:noSimilarItem","message":"no similar item found for item1","data":{"item1FeatureId":"seats","item1Interval":"month","item1IncludedUsage":25,"items2Count":2,"items2FeatureIds":["analytics","messages"]},"timestamp":1768767575485,"sessionId":"debug-session","hypothesisId":"H2-H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768767861061,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768767861062,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768492990,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768492990,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768494722,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768494722,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768494856,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768494857,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768503769,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768503770,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":null,"included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":null}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768509714,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":null,"included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":null}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768509714,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":0}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768510972,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":0}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768510973,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":0}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768512258,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":0}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768512259,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":4}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768513093,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":4}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768513093,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":4}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768513323,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":4}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768513323,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"compareItemUtils.ts:featurePriceItemsAreSame","message":"feature price items comparison failed","data":{"featureId":"seats","failedEntChecks":[{"check":"included_usage","message":"Included usage different: null != 0"}],"failedPriceChecks":[],"item1":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":null,\"interval\":\"month\",\"price\":4,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false,\"usage_model\":\"pay_per_use\",\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","item2":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":0,\"interval\":\"month\",\"interval_count\":1,\"price\":4,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false,\"usage_model\":\"pay_per_use\",\"created_at\":1768768517976,\"entitlement_id\":\"ent_38Rhv08gZdC1AOrMvs20Gt4exbK\",\"price_id\":\"pr_38RhuzPJAjXGGc5JaF7JBQnKclZ\",\"price_config\":{\"type\":\"usage\",\"interval\":\"month\",\"bill_when\":\"end_of_period\",\"feature_id\":\"seats\",\"usage_tiers\":[{\"to\":\"inf\",\"amount\":4}],\"billing_units\":1,\"interval_count\":1,\"should_prorate\":true,\"stripe_price_id\":\"price_1Sr2gtG2wlWesuVT9hSb0qPO\",\"stripe_product_id\":\"prod_Tog21hujMdhsAJ\",\"internal_feature_id\":\"fe_38IUUvu4BoVK96JwbDZfJHwcRyD\",\"stripe_placeholder_price_id\":\"price_1Sr2guG2wlWesuVTfbCs2bkT\"},\"config\":{\"on_decrease\":\"prorate_immediately\",\"on_increase\":\"prorate_immediately\"},\"usage_limit\":null}"},"timestamp":1768768522738,"sessionId":"debug-session","hypothesisId":"H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":4}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768522738,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"compareItemUtils.ts:featurePriceItemsAreSame","message":"feature price items comparison failed","data":{"featureId":"seats","failedEntChecks":[{"check":"included_usage","message":"Included usage different: null != 0"}],"failedPriceChecks":[],"item1":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":null,\"interval\":\"month\",\"price\":4,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false,\"usage_model\":\"pay_per_use\",\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","item2":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":0,\"interval\":\"month\",\"interval_count\":1,\"price\":4,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false,\"usage_model\":\"pay_per_use\",\"created_at\":1768768517976,\"entitlement_id\":\"ent_38Rhv08gZdC1AOrMvs20Gt4exbK\",\"price_id\":\"pr_38RhuzPJAjXGGc5JaF7JBQnKclZ\",\"price_config\":{\"type\":\"usage\",\"interval\":\"month\",\"bill_when\":\"end_of_period\",\"feature_id\":\"seats\",\"usage_tiers\":[{\"to\":\"inf\",\"amount\":4}],\"billing_units\":1,\"interval_count\":1,\"should_prorate\":true,\"stripe_price_id\":\"price_1Sr2gtG2wlWesuVT9hSb0qPO\",\"stripe_product_id\":\"prod_Tog21hujMdhsAJ\",\"internal_feature_id\":\"fe_38IUUvu4BoVK96JwbDZfJHwcRyD\",\"stripe_placeholder_price_id\":\"price_1Sr2guG2wlWesuVTfbCs2bkT\"},\"config\":{\"on_decrease\":\"prorate_immediately\",\"on_increase\":\"prorate_immediately\"},\"usage_limit\":null}"},"timestamp":1768768522739,"sessionId":"debug-session","hypothesisId":"H3"}
{"location":"compareItemUtils.ts:featurePriceItemsAreSame","message":"feature price items comparison failed","data":{"featureId":"seats","failedEntChecks":[{"check":"included_usage","message":"Included usage different: null != 0"}],"failedPriceChecks":[],"item1":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":null,\"interval\":\"month\",\"price\":4,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false,\"usage_model\":\"pay_per_use\",\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","item2":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":0,\"interval\":\"month\",\"interval_count\":1,\"price\":4,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false,\"usage_model\":\"pay_per_use\",\"created_at\":1768768517976,\"entitlement_id\":\"ent_38Rhv08gZdC1AOrMvs20Gt4exbK\",\"price_id\":\"pr_38RhuzPJAjXGGc5JaF7JBQnKclZ\",\"price_config\":{\"type\":\"usage\",\"interval\":\"month\",\"bill_when\":\"end_of_period\",\"feature_id\":\"seats\",\"usage_tiers\":[{\"to\":\"inf\",\"amount\":4}],\"billing_units\":1,\"interval_count\":1,\"should_prorate\":true,\"stripe_price_id\":\"price_1Sr2gtG2wlWesuVT9hSb0qPO\",\"stripe_product_id\":\"prod_Tog21hujMdhsAJ\",\"internal_feature_id\":\"fe_38IUUvu4BoVK96JwbDZfJHwcRyD\",\"stripe_placeholder_price_id\":\"price_1Sr2guG2wlWesuVTfbCs2bkT\"},\"config\":{\"on_decrease\":\"prorate_immediately\",\"on_increase\":\"prorate_immediately\"},\"usage_limit\":null}"},"timestamp":1768768522738,"sessionId":"debug-session","hypothesisId":"H3"}
{"location":"compareItemUtils.ts:featurePriceItemsAreSame","message":"feature price items comparison failed","data":{"featureId":"seats","failedEntChecks":[{"check":"included_usage","message":"Included usage different: null != 0"}],"failedPriceChecks":[],"item1":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":null,\"interval\":\"month\",\"price\":4,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false,\"usage_model\":\"pay_per_use\",\"config\":{\"on_increase\":\"prorate_immediately\",\"on_decrease\":\"prorate_immediately\"}}","item2":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":0,\"interval\":\"month\",\"interval_count\":1,\"price\":4,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false,\"usage_model\":\"pay_per_use\",\"created_at\":1768768517976,\"entitlement_id\":\"ent_38Rhv08gZdC1AOrMvs20Gt4exbK\",\"price_id\":\"pr_38RhuzPJAjXGGc5JaF7JBQnKclZ\",\"price_config\":{\"type\":\"usage\",\"interval\":\"month\",\"bill_when\":\"end_of_period\",\"feature_id\":\"seats\",\"usage_tiers\":[{\"to\":\"inf\",\"amount\":4}],\"billing_units\":1,\"interval_count\":1,\"should_prorate\":true,\"stripe_price_id\":\"price_1Sr2gtG2wlWesuVT9hSb0qPO\",\"stripe_product_id\":\"prod_Tog21hujMdhsAJ\",\"internal_feature_id\":\"fe_38IUUvu4BoVK96JwbDZfJHwcRyD\",\"stripe_placeholder_price_id\":\"price_1Sr2guG2wlWesuVTfbCs2bkT\"},\"config\":{\"on_decrease\":\"prorate_immediately\",\"on_increase\":\"prorate_immediately\"},\"usage_limit\":null}"},"timestamp":1768768522739,"sessionId":"debug-session","hypothesisId":"H3"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":4}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768522739,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768616773,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768616773,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768617686,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768617687,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768619603,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768619604,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768627805,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768627805,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":null,"included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":null}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768634551,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":null,"included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":null}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768634551,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":0}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768635559,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":0}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768635559,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":4}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768636851,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":4}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768636851,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":4}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768637168,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":4}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768637169,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":4}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768647252,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":[{"to":"inf","amount":4}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768647253,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768650150,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768650151,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":null,"reset_usage_when_enabled":true,"price":null,"tiers":null}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768653414,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":null,"reset_usage_when_enabled":true,"price":null,"tiers":null}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768653414,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":null,"reset_usage_when_enabled":true,"price":null,"tiers":[{"to":"inf","amount":0}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768654738,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":null,"reset_usage_when_enabled":true,"price":null,"tiers":[{"to":"inf","amount":0}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768654738,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":null,"reset_usage_when_enabled":true,"price":null,"tiers":[{"to":"inf","amount":5}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768656050,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":null,"reset_usage_when_enabled":true,"price":null,"tiers":[{"to":"inf","amount":5}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768656050,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":null,"reset_usage_when_enabled":true,"price":null,"tiers":[{"to":"inf","amount":5}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768656372,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":null,"reset_usage_when_enabled":true,"price":null,"tiers":[{"to":"inf","amount":5}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":"month","included_usage":0,"reset_usage_when_enabled":false,"price":null,"tiers":[{"amount":4,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768656373,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":null,"reset_usage_when_enabled":true,"price":null,"tiers":[{"to":"inf","amount":5}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768657946,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":null,"reset_usage_when_enabled":true,"price":null,"tiers":[{"to":"inf","amount":5}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768657947,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":null,"reset_usage_when_enabled":true,"price":null,"tiers":[{"to":"inf","amount":5}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":0,"reset_usage_when_enabled":true,"price":null,"tiers":[{"amount":5,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768668632,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":null,"reset_usage_when_enabled":true,"price":null,"tiers":[{"to":"inf","amount":5}],"usage_model":"pay_per_use"}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":0,"reset_usage_when_enabled":true,"price":null,"tiers":[{"amount":5,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768668633,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":0,"reset_usage_when_enabled":true,"price":null,"tiers":[{"amount":5,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768670093,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":1,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":0,"reset_usage_when_enabled":true,"price":null,"tiers":[{"amount":5,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768670094,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":null,"included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":null}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":0,"reset_usage_when_enabled":true,"price":null,"tiers":[{"amount":5,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768675489,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":null,"included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":null}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"runs","feature_type":"single_use","interval":"month","included_usage":0,"reset_usage_when_enabled":true,"price":null,"tiers":[{"amount":5,"to":"inf"}],"usage_model":"pay_per_use"}]},"timestamp":1768768675489,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":null,"included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":null}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768677586,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":null,"included_usage":null,"reset_usage_when_enabled":false,"price":null,"tiers":null}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768677586,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":null,"included_usage":5,"reset_usage_when_enabled":false,"price":null,"tiers":null}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768678144,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":true,"itemsSame":false,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":1,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":null,"included_usage":5,"reset_usage_when_enabled":false,"price":null,"tiers":null}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true}]},"timestamp":1768768678144,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"compareItemUtils.ts:featureItemsAreSame","message":"feature items comparison failed","data":{"featureId":"seats","failedChecks":[{"check":"included_usage","message":"Included usage different: 5 != null"}],"item1":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":5,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false}","item2":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":null,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false}"},"timestamp":1768768678144,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"compareItemUtils.ts:featureItemsAreSame","message":"feature items comparison failed","data":{"featureId":"seats","failedChecks":[{"check":"included_usage","message":"Included usage different: 5 != null"}],"item1":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":5,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false}","item2":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":null,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false}"},"timestamp":1768768678145,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"compareItemUtils.ts:featureItemsAreSame","message":"feature items comparison failed","data":{"featureId":"seats","failedChecks":[{"check":"included_usage","message":"Included usage different: 5 != null"}],"item1":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":5,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false}","item2":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":null,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false}"},"timestamp":1768768678145,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"compareItemUtils.ts:featureItemsAreSame","message":"feature items comparison failed","data":{"featureId":"seats","failedChecks":[{"check":"included_usage","message":"Included usage different: 5 != null"}],"item1":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":5,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false}","item2":"{\"feature_id\":\"seats\",\"feature_type\":\"continuous_use\",\"included_usage\":null,\"interval\":null,\"price\":null,\"tiers\":null,\"billing_units\":1,\"entity_feature_id\":null,\"reset_usage_when_enabled\":false}"},"timestamp":1768768678145,"sessionId":"debug-session","hypothesisId":"H2"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":null,"included_usage":5,"reset_usage_when_enabled":false,"price":null,"tiers":null}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":null,"included_usage":5,"reset_usage_when_enabled":false}]},"timestamp":1768768686901,"sessionId":"debug-session","hypothesisId":"H1"}
{"location":"useProductStore.ts:useHasChanges","message":"hasChanges computed","data":{"hasChanges":false,"itemsSame":true,"detailsSame":true,"freeTrialsSame":true,"productItemsCount":2,"baseProductItemsCount":2,"productItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":null,"included_usage":5,"reset_usage_when_enabled":false,"price":null,"tiers":null}],"baseProductItems":[{"feature_id":"messages","feature_type":"single_use","interval":null,"included_usage":10,"reset_usage_when_enabled":true},{"feature_id":"seats","feature_type":"continuous_use","interval":null,"included_usage":5,"reset_usage_when_enabled":false}]},"timestamp":1768768686901,"sessionId":"debug-session","hypothesisId":"H1"}

View File

@@ -10,12 +10,14 @@ import {
and,
desc,
eq,
gt, ilike, isNotNull,
gt,
ilike,
isNotNull,
isNull,
lt,
notExists,
or,
sql
sql,
} from "drizzle-orm";
import { alias } from "drizzle-orm/pg-core";
import type { DrizzleCli } from "@/db/initDrizzle.js";
@@ -155,6 +157,16 @@ export class CusSearchService {
? or(
...statuses.map((status) => {
switch (status) {
case "active":
return and(
eq(customerProducts.status, CusProductStatus.Active),
isNull(customerProducts.canceled_at),
);
case "past_due":
return and(
eq(customerProducts.status, CusProductStatus.PastDue),
isNull(customerProducts.canceled_at),
);
case "canceled":
return and(
isNotNull(customerProducts.canceled_at),
@@ -164,6 +176,7 @@ export class CusSearchService {
return and(
gt(customerProducts.trial_ends_at, Date.now()),
isNotNull(customerProducts.free_trial_id),
isNull(customerProducts.canceled_at),
activeProdFilter,
);
case CusProductStatus.Expired:
@@ -513,7 +526,8 @@ export class CusSearchService {
});
}
if (filters?.version && filters?.version.length > 0) {
// Call searchByProduct if we have version filters OR status filters
if ((filters?.version && filters?.version.length > 0) || (filters?.status && filters?.status.length > 0)) {
return await CusSearchService.searchByProduct({
db,
orgId,
@@ -642,7 +656,6 @@ export class CusSearchService {
return { data: finalResults, count: totalCount };
}
}
// // Legacy support for product_id field (if still used)
// let productIds: string[] = [];
// if (filters.product_id) {

View File

@@ -1,4 +1,7 @@
import { FeatureType } from "../models/featureModels/featureEnums.js";
import {
FeatureType,
FeatureUsageType,
} from "../models/featureModels/featureEnums.js";
import type { Feature } from "../models/featureModels/featureModels.js";
import { Infinite } from "../models/productModels/productEnums.js";
import type { ProductItem } from "../models/productV2Models/productItemModels/productItemModels.js";
@@ -12,40 +15,84 @@ import {
} from "./productV2Utils/productItemUtils/getItemType.js";
import { notNullish, nullish } from "./utils.js";
// ============================================================================
// Types
// ============================================================================
interface DisplayResult {
primary_text: string;
secondary_text?: string;
}
interface FormatTiersParams {
item: ProductItem;
currency?: string | null;
amountFormatOptions?: Intl.NumberFormatOptions;
}
// ============================================================================
// Helpers
// ============================================================================
const getIntervalDisplay = (item: ProductItem): string | undefined => {
if (!item.interval) return undefined;
return formatInterval({
interval: item.interval,
intervalCount: item.interval_count ?? undefined,
});
};
const getIncludedUsageText = (item: ProductItem, feature: Feature): string => {
const featureName = getFeatureName({
feature,
units: item.included_usage,
});
if (item.included_usage === Infinite) {
return `Unlimited ${featureName}`;
}
if (nullish(item.included_usage) || item.included_usage === 0) {
return `0 ${featureName}`;
}
return `${numberWithCommas(item.included_usage)} ${featureName}`;
};
const isSingleUseFeature = (feature: Feature): boolean => {
return feature.config?.usage_type === FeatureUsageType.Single;
};
// ============================================================================
// Tier Formatting
// ============================================================================
export const formatTiers = ({
item,
currency,
amountFormatOptions,
}: {
item: ProductItem;
currency?: string | null;
amountFormatOptions?: Intl.NumberFormatOptions;
}) => {
}: FormatTiersParams): string | undefined => {
const tiers = item.tiers;
if (tiers) {
if (tiers.length === 1) {
return formatAmount({
currency,
amount: tiers[0].amount,
amountFormatOptions,
});
}
if (!tiers) return undefined;
const firstPrice = tiers[0].amount;
const lastPrice = tiers[tiers.length - 1].amount;
const format = (amount: number) =>
formatAmount({ currency, amount, amountFormatOptions });
return `${formatAmount({
currency,
amount: firstPrice,
amountFormatOptions,
})} - ${formatAmount({
currency,
amount: lastPrice,
amountFormatOptions,
})}`;
if (tiers.length === 1) {
return format(tiers[0].amount);
}
const firstPrice = tiers[0].amount;
const lastPrice = tiers[tiers.length - 1].amount;
return `${format(firstPrice)} - ${format(lastPrice)}`;
};
// ============================================================================
// Feature Item Display (no pricing, just entitlement)
// ============================================================================
export const getFeatureItemDisplay = ({
item,
feature,
@@ -54,57 +101,30 @@ export const getFeatureItemDisplay = ({
item: ProductItem;
feature?: Feature;
fullDisplay?: boolean;
}) => {
if (!feature) throw new Error(`Feature ${item.feature_id} not found`);
}): DisplayResult => {
if (!feature) {
// Return fallback display when feature is not found (e.g., during feature ID rename)
return { primary_text: item.feature_id || "Loading..." };
}
// Boolean features just show the name
if (feature.type === FeatureType.Boolean) {
return { primary_text: feature.name };
}
const featureName = getFeatureName({
feature,
units: item.included_usage,
});
const primaryText = getIncludedUsageText(item, feature);
const includedUsageTxt =
item.included_usage === Infinite
? "Unlimited "
: nullish(item.included_usage) || item.included_usage === 0
? "0 "
: `${numberWithCommas(item.included_usage)} `;
// If interval is null for a feature item, it's a one-time/lifetime feature
const intervalStr = item.interval
? formatInterval({
interval: item.interval,
intervalCount: item.interval_count ?? undefined,
})
: "one-off";
return {
primary_text: `${includedUsageTxt}${featureName}`,
secondary_text: fullDisplay ? intervalStr : undefined,
};
};
export const getPriceItemDisplay = ({
item,
currency,
}: {
item: ProductItem;
currency?: string | null;
}) => {
const primaryText = formatAmount({
currency,
amount: item.price as number,
});
const intervalStr = formatInterval({
interval: item.interval ?? undefined,
intervalCount: item.interval_count ?? undefined,
});
const secondaryText = intervalStr || undefined;
// Determine secondary text (interval display)
let secondaryText: string | undefined;
if (fullDisplay) {
const intervalDisplay = getIntervalDisplay(item);
if (intervalDisplay) {
secondaryText = intervalDisplay;
} else if (isSingleUseFeature(feature)) {
// Only show "one-off" for single-use features, not continuous use
secondaryText = "one-off";
}
}
return {
primary_text: primaryText,
@@ -112,12 +132,39 @@ export const getPriceItemDisplay = ({
};
};
// ============================================================================
// Price Item Display (flat price, no feature)
// ============================================================================
export const getPriceItemDisplay = ({
item,
currency,
}: {
item: ProductItem;
currency?: string | null;
}): DisplayResult => {
const primaryText = formatAmount({
currency,
amount: item.price as number,
});
const secondaryText = getIntervalDisplay(item);
return {
primary_text: primaryText,
secondary_text: secondaryText,
};
};
// ============================================================================
// Feature + Price Item Display (usage-based pricing)
// ============================================================================
export const getFeaturePriceItemDisplay = ({
feature,
item,
currency,
isMainPrice = false,
// minifyIncluded = false,
amountFormatOptions,
fullDisplay = false,
}: {
@@ -125,73 +172,77 @@ export const getFeaturePriceItemDisplay = ({
item: ProductItem;
currency?: string | null;
isMainPrice?: boolean;
// minifyIncluded?: boolean;
amountFormatOptions?: Intl.NumberFormatOptions;
fullDisplay?: boolean;
}) => {
}): DisplayResult => {
if (!feature) {
throw new Error(`Feature ${item.feature_id} not found`);
}
// 1. Get included usage
// Build included usage string (e.g., "100 credits")
const includedUsage = item.included_usage as number | null;
const hasIncludedUsage = notNullish(includedUsage) && includedUsage > 0;
const includedFeatureName = getFeatureName({
feature,
units: item.included_usage,
});
const includedUsageStr = hasIncludedUsage
? `${numberWithCommas(includedUsage)} ${includedFeatureName}`
: "";
const includedUsage = item.included_usage as number | null;
let includedUsageStr = "";
if (notNullish(includedUsage) && includedUsage > 0) {
includedUsageStr = `${numberWithCommas(includedUsage)} ${includedFeatureName}`;
}
// Build price string (e.g., "$0.01")
const priceStr = formatTiers({ item, currency, amountFormatOptions }) ?? "";
// For "per X" display, use singular when billing_units is 1 or not specified
// Build billing unit string (e.g., "credit" or "100 credits")
const billingUnits = item.billing_units ?? 1;
const billingFeatureName = getFeatureName({
feature,
units: billingUnits,
});
const perUnitStr =
billingUnits > 1
? `${numberWithCommas(billingUnits)} ${billingFeatureName}`
: billingFeatureName;
let priceStr2 = "";
if (billingUnits > 1) {
priceStr2 = `${numberWithCommas(billingUnits)} ${billingFeatureName}`;
} else {
priceStr2 = `${billingFeatureName}`;
// Build interval string
const showInterval = isMainPrice || fullDisplay;
let intervalStr = "";
if (showInterval) {
const intervalDisplay = getIntervalDisplay(item);
if (intervalDisplay) {
intervalStr = intervalDisplay;
} else if (isSingleUseFeature(feature)) {
intervalStr = "one-off";
}
}
// If interval is null for a priced feature, it's a one-time purchase
const intervalStr =
isMainPrice || fullDisplay
? item.interval
? formatInterval({
interval: item.interval,
intervalCount: item.interval_count ?? undefined,
})
: "one-off"
: "";
if (includedUsageStr) {
// Format output based on what we have
if (hasIncludedUsage) {
return {
primary_text: includedUsageStr,
secondary_text: `then ${priceStr} per ${priceStr2} ${intervalStr}`,
secondary_text:
`then ${priceStr} per ${perUnitStr} ${intervalStr}`.trim(),
};
}
if (isMainPrice || fullDisplay) {
if (showInterval) {
return {
primary_text: priceStr,
secondary_text: `per ${priceStr2} ${intervalStr}`,
secondary_text: `per ${perUnitStr} ${intervalStr}`.trim(),
};
}
return {
primary_text: `${priceStr} per ${priceStr2} ${intervalStr}`,
primary_text: `${priceStr} per ${perUnitStr}`.trim(),
secondary_text: undefined,
};
};
// ============================================================================
// Main Entry Point
// ============================================================================
export const getProductItemDisplay = ({
item,
features,
@@ -204,26 +255,25 @@ export const getProductItemDisplay = ({
currency?: string | null;
fullDisplay?: boolean;
amountFormatOptions?: Intl.NumberFormatOptions;
}) => {
}): DisplayResult => {
const findFeature = () => features.find((f) => f.id === item.feature_id);
if (isFeatureItem(item)) {
return getFeatureItemDisplay({
item,
feature: features.find((f) => f.id === item.feature_id),
feature: findFeature(),
fullDisplay,
});
}
if (isPriceItem(item)) {
return getPriceItemDisplay({
item,
currency,
});
return getPriceItemDisplay({ item, currency });
}
if (isFeaturePriceItem(item)) {
return getFeaturePriceItemDisplay({
item,
feature: features.find((f) => f.id === item.feature_id),
feature: findFeature(),
currency,
fullDisplay,
amountFormatOptions,

View File

@@ -103,6 +103,12 @@ const tiersAreSame = (
);
};
// Helper to normalize included_usage for comparison (null and 0 are equivalent)
const normalizeIncludedUsage = (value: number | "inf" | null | undefined) => {
if (value === null || value === undefined) return 0;
return value;
};
export const featureItemsAreSame = ({
item1,
item2,
@@ -118,7 +124,10 @@ export const featureItemsAreSame = ({
message: `Feature ID different: ${item1.feature_id} != ${item2.feature_id}`,
},
included_usage: {
condition: item1.included_usage == item2.included_usage,
// Normalize null/undefined to 0 for comparison since they're semantically equivalent
condition:
normalizeIncludedUsage(item1.included_usage) ==
normalizeIncludedUsage(item2.included_usage),
message: `Included usage different: ${item1.included_usage} != ${item2.included_usage}`,
},
interval: {
@@ -232,7 +241,10 @@ export const featurePriceItemsAreSame = ({
// console.log("Item 2 config:", item2.config);
const entsSame = {
included_usage: {
condition: item1.included_usage == item2.included_usage,
// Normalize null/undefined to 0 for comparison since they're semantically equivalent
condition:
normalizeIncludedUsage(item1.included_usage) ==
normalizeIncludedUsage(item2.included_usage),
message: `Included usage different: ${item1.included_usage} != ${item2.included_usage}`,
},
usage_limit: {

View File

@@ -14,7 +14,7 @@ function SortIcon({ sortDirection }: { sortDirection: string | false }) {
return (
<ChevronUpIcon
aria-hidden="true"
className="shrink-0 opacity-60"
className="shrink-0 text-primary"
size={16}
/>
);
@@ -23,7 +23,7 @@ function SortIcon({ sortDirection }: { sortDirection: string | false }) {
return (
<ChevronDownIcon
aria-hidden="true"
className={cn("shrink-0", sortDirection ? "opacity-60" : "opacity-30")}
className={cn("shrink-0", sortDirection ? "text-primary" : "opacity-30")}
size={16}
/>
);

View File

@@ -3,6 +3,7 @@ import { AnimatePresence, motion } from "motion/react";
import { createPortal } from "react-dom";
import { Button } from "@/components/v2/buttons/Button";
import { ShortcutButton } from "@/components/v2/buttons/ShortcutButton";
import { SheetOverlay } from "@/components/v2/sheet-overlay/SheetOverlay";
import { cn } from "@/lib/utils";
import { CustomerPlanInfoBox } from "@/views/customers2/customer-plan/CustomerPlanInfoBox";
import { EditPlanHeader } from "@/views/products/plan/components/EditPlanHeader";
@@ -53,7 +54,7 @@ function InlinePlanEditorContent({
onCancel: () => void;
}) {
const { product } = useProduct();
const { sheetType, closeSheet } = useSheet();
const { sheetType } = useSheet();
const hasPlanChanges = useHasPlanChanges();
return (
@@ -63,6 +64,7 @@ function InlinePlanEditorContent({
exit={{ opacity: 0, scale: 0.97, y: 8 }}
transition={{ duration: 0.2, ease: [0.16, 1, 0.3, 1] }}
className="absolute inset-0 z-100 bg-background flex flex-col"
data-inline-editor-open
>
<div className="flex w-full h-full overflow-hidden relative flex-1">
<motion.div
@@ -99,18 +101,7 @@ function InlinePlanEditorContent({
</div>
</motion.div>
<AnimatePresence>
{sheetType && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="absolute inset-0 bg-white/70 dark:bg-black/70"
style={{ zIndex: 40 }}
onMouseDown={() => closeSheet()}
/>
)}
</AnimatePresence>
<SheetOverlay inline />
<ProductSheets />
</div>

View File

@@ -104,8 +104,8 @@ function SelectContent({
<SelectPrimitive.Content
data-slot="select-content"
className={cn(
// Change z-50 to z-[101] or higher to beat the sheet's z-100
"bg-interactive-secondary text-popover-foreground relative z-[101] max-h-(--radix-select-content-available-height) min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
// z-[200] to appear above sheets (z-[150])
"bg-interactive-secondary text-popover-foreground relative z-[200] max-h-(--radix-select-content-available-height) min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",

View File

@@ -0,0 +1,105 @@
import type { ProductItem } from "@autumn/shared";
import { AnimatePresence, motion } from "motion/react";
import { createPortal } from "react-dom";
import {
useCurrentItem,
useHasItemChanges,
useSheet,
} from "@/components/v2/inline-custom-plan-editor/PlanEditorContext";
/**
* Determines if the sheet should close based on the mouse down event.
* Handles edge cases like unsaved changes and input blur behavior.
*/
function shouldCloseSheetOnMouseDown({
e,
item,
sheetType,
hasItemChanges,
}: {
e: React.MouseEvent<HTMLDivElement>;
item: ProductItem | null;
sheetType: string | null;
hasItemChanges: boolean;
}): boolean {
// Don't close if item has unsaved changes
if (hasItemChanges) {
return false;
}
// Get the active element before blur happens
const activeElement = document.activeElement;
if (
activeElement &&
activeElement !== document.body &&
activeElement instanceof HTMLElement
) {
// Only apply blur behavior to inputs, textareas, and selects
const isInputElement =
activeElement.tagName === "INPUT" ||
activeElement.tagName === "TEXTAREA" ||
activeElement.tagName === "SELECT";
if (!isInputElement) {
// Not an input, proceed with normal close behavior
return !!sheetType;
}
// Check if the active element is within the sheet (not in the main content area)
const clickTarget = e.target as HTMLElement;
const isActiveInSheet = !clickTarget.contains(activeElement);
if (isActiveInSheet) {
activeElement.blur();
e.preventDefault(); // Prevent default to stop the click from propagating
return false;
}
}
// If the click is outside the sheet and no input is focused, close the sheet
return !!sheetType;
}
/**
* Shared overlay component for plan editors.
* Portals to [data-main-content] by default, or renders inline if `inline` prop is true.
*/
export function SheetOverlay({ inline = false }: { inline?: boolean }) {
const { sheetType, closeSheet } = useSheet();
const item = useCurrentItem();
const hasItemChanges = useHasItemChanges();
const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
if (shouldCloseSheetOnMouseDown({ e, item, sheetType, hasItemChanges })) {
closeSheet();
}
};
const overlay = (
<AnimatePresence>
{sheetType && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="absolute inset-0 bg-white/70 dark:bg-black/70"
style={{ zIndex: 40 }}
onMouseDown={handleMouseDown}
/>
)}
</AnimatePresence>
);
if (inline) {
return overlay;
}
const mainContent = document.querySelector("[data-main-content]");
if (!mainContent) {
console.error("[SheetOverlay] Could not find portal target");
return null;
}
return createPortal(overlay, mainContent);
}

View File

@@ -14,6 +14,7 @@ interface SheetHeaderProps {
isOnboarding?: boolean;
breadcrumbs?: { name: string; sheet?: string }[];
itemId?: string | null;
action?: React.ReactNode;
}
export function SheetHeader({
@@ -25,6 +26,7 @@ export function SheetHeader({
className,
isOnboarding = false,
itemId,
action,
}: SheetHeaderProps) {
return (
<div className={cn("p-4 pb-0", className)}>
@@ -37,16 +39,19 @@ export function SheetHeader({
) : (
<h2 className="text-main">{title}</h2>
)}
<p
className={cn(
"text-t3 text-sm mt-1 truncate",
isOnboarding && "text-body-secondary",
)}
>
{description}
</p>
<div className="flex items-end justify-between gap-2 mt-1">
<p
className={cn(
"text-t3 text-sm flex-1",
isOnboarding && "text-body-secondary",
)}
>
{description}
</p>
{action}
</div>
{children}
{!noSeparator && <Separator className="mt-4" />}
{!noSeparator && <Separator className="mt-2" />}
</div>
);
}

View File

@@ -1,13 +1,10 @@
"use client";
import { AppEnv } from "@autumn/shared";
import * as SheetPrimitive from "@radix-ui/react-dialog";
import { XIcon } from "lucide-react";
import type * as React from "react";
import { usePortalContainer } from "@/contexts/PortalContainerContext";
import { cn } from "@/lib/utils";
import { useEnv } from "@/utils/envUtils";
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
return <SheetPrimitive.Root data-slot="sheet" {...props} />;
@@ -28,11 +25,11 @@ function SheetClose({
function SheetPortal({
...props
}: React.ComponentProps<typeof SheetPrimitive.Portal>) {
const containerRef = usePortalContainer();
const mainContent = document.querySelector("[data-main-content]");
return (
<SheetPrimitive.Portal
data-slot="sheet-portal"
container={containerRef?.current ?? undefined}
container={mainContent ?? undefined}
{...props}
/>
);
@@ -46,7 +43,7 @@ function SheetOverlay({
<SheetPrimitive.Overlay
data-slot="sheet-overlay"
className={cn(
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-white/70 dark:bg-black/70",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 absolute inset-0 z-[150] bg-white/70 dark:bg-black/70",
className,
)}
{...props}
@@ -64,25 +61,17 @@ function SheetContent({
side?: "top" | "right" | "bottom" | "left";
hideCloseButton?: boolean;
}) {
const env = useEnv();
const isSandbox = env === AppEnv.Sandbox;
return (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
data-slot="sheet-content"
style={
(side === "right" || side === "left") && isSandbox
? { top: "40px" }
: undefined
}
className={cn(
"bg-card data-[state=open]:animate-in data-[state=closed]:animate-out absolute z-50 flex flex-col gap-0 shadow-sm transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-300",
"bg-card data-[state=open]:animate-in data-[state=closed]:animate-out absolute z-[150] flex flex-col gap-0 shadow-sm transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-300",
side === "right" &&
`data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right ${isSandbox ? "" : "top-0"} bottom-0 right-0 w-full min-w-xs max-w-md border-l border-border/40`,
`data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right top-0 bottom-0 right-0 w-full min-w-xs max-w-md border-l border-border/40`,
side === "left" &&
`data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left ${isSandbox ? "" : "top-0"} bottom-0 left-0 w-3/4 border-r border-border/40 sm:max-w-sm`,
`data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left top-0 bottom-0 left-0 w-3/4 border-r border-border/40 sm:max-w-sm`,
side === "top" &&
"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top left-0 right-0 top-0 h-auto border-b border-border/40",
side === "bottom" &&

View File

@@ -122,8 +122,12 @@ export const useSheetEscapeHandler = ({
document.querySelector('[data-state="open"][role="alertdialog"]') ||
document.querySelector("dialog[open]");
const isInlineEditorOpen = document.querySelector(
"[data-inline-editor-open]",
);
// Only close sheet if no dialog is open
if (!isDialogOpen) {
if (!isDialogOpen && !isInlineEditorOpen) {
// Use custom onClose if provided, otherwise default closeSheet
if (onClose) {
onClose();

View File

@@ -40,7 +40,7 @@ function CustomersFilterButton() {
<DropdownMenu open={open} onOpenChange={setOpen}>
<RenderFilterTrigger />
<DropdownMenuContent
className="w-56 font-regular text-zinc-800 gap-0 p-0"
className="w-56 font-regular gap-0 p-0"
align="start"
>
<DropdownMenuGroup className="p-1">

View File

@@ -1,17 +1,23 @@
import { Checkbox } from "@/components/v2/checkboxes/Checkbox";
import {
DropdownMenuItem,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuItem,
} from "@/components/v2/dropdowns/DropdownMenu";
import { Checkbox } from "@/components/v2/checkboxes/Checkbox";
import { keyToTitle } from "@/utils/formatUtils/formatTextUtils";
import { useCustomersQueryStates } from "../../hooks/useCustomersQueryStates";
export const FilterStatusSubMenu = () => {
const { queryStates, setQueryStates } = useCustomersQueryStates();
const { queryStates, setFilters } = useCustomersQueryStates();
const statuses: string[] = ["canceled", "free_trial", "expired"];
const statuses: string[] = [
"active",
"past_due",
"canceled",
"free_trial",
"expired",
];
const selectedStatuses = queryStates.status || [];
const hasSelections = selectedStatuses.length > 0;
@@ -23,7 +29,7 @@ export const FilterStatusSubMenu = () => {
? selected.filter((s: string) => s !== status)
: [...selected, status];
setQueryStates({ ...queryStates, status: updated });
setFilters({ status: updated });
};
return (

View File

@@ -1,19 +1,19 @@
import { Checkbox } from "@/components/v2/checkboxes/Checkbox";
import {
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuSeparator,
DropdownMenuItem,
} from "@/components/v2/dropdowns/DropdownMenu";
import { Checkbox } from "@/components/v2/checkboxes/Checkbox";
import { cn } from "@/lib/utils";
import { useCustomersQueryStates } from "../../hooks/useCustomersQueryStates";
import { useProductsQuery } from "@/hooks/queries/useProductsQuery";
import { cn } from "@/lib/utils";
import { getVersionCounts } from "@/utils/productUtils";
import { useCustomersQueryStates } from "../../hooks/useCustomersQueryStates";
export const ProductsSubMenu = () => {
const { products } = useProductsQuery();
const { queryStates, setQueryStates } = useCustomersQueryStates();
const { queryStates, setFilters } = useCustomersQueryStates();
const versionCounts = getVersionCounts(products);
const selectedVersions = queryStates.version;
@@ -63,14 +63,9 @@ export const ProductsSubMenu = () => {
allProductVersions.length > 0 &&
allProductVersions.every((pv) => selectedVersions.includes(pv.key));
if (allSelected) {
setQueryStates({
...queryStates,
version: [],
none: false,
});
setFilters({ version: [], none: false });
} else {
setQueryStates({
...queryStates,
setFilters({
version: allProductVersions.map((pv) => pv.key),
none: false,
});
@@ -88,7 +83,7 @@ export const ProductsSubMenu = () => {
selectedVersions.includes(key),
);
let newSelectedVersions;
let newSelectedVersions: string[] = [];
let newNone = queryStates.none;
if (allProductVersionsSelected) {
// Deselect all versions of this product
@@ -104,18 +99,14 @@ export const ProductsSubMenu = () => {
newNone = false;
}
setQueryStates({
...queryStates,
version: newSelectedVersions,
none: newNone,
});
setFilters({ version: newSelectedVersions, none: newNone });
};
const toggleVersion = (productId: string, version: string) => {
const versionKey = `${productId}:${version}`;
const isSelected = selectedVersions.includes(versionKey);
let newSelectedVersions;
let newSelectedVersions: string[] = [];
let newNone = queryStates.none;
if (isSelected) {
newSelectedVersions = selectedVersions.filter(
@@ -126,28 +117,20 @@ export const ProductsSubMenu = () => {
newNone = false;
}
setQueryStates({
...queryStates,
version: newSelectedVersions,
none: newNone,
});
setFilters({ version: newSelectedVersions, none: newNone });
};
const handleSelectNone = (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
setQueryStates({
...queryStates,
version: [],
none: !queryStates.none,
});
setFilters({ version: [], none: !queryStates.none });
};
return (
<DropdownMenuSub>
<DropdownMenuSubTrigger className="flex items-center gap-2 cursor-pointer">
Products
Plans
{hasSelections && (
<span className="text-xs text-t3 bg-muted px-1 py-0 rounded-md">
{selectedProductsCount}
@@ -163,17 +146,21 @@ export const ProductsSubMenu = () => {
<>
<div className="flex items-center justify-between px-2 h-6">
<button
type="button"
onClick={handleSelectAll}
className={cn(
"px-1 h-5 flex items-center gap-1 text-t2 text-xs hover:text-t1 bg-accent cursor-pointer rounded-md",
allProductVersions.length > 0 &&
allProductVersions.every((pv) => selectedVersions.includes(pv.key)) &&
allProductVersions.every((pv) =>
selectedVersions.includes(pv.key),
) &&
"bg-primary/10 text-primary hover:text-primary/80",
)}
>
Select all
</button>
<button
type="button"
onClick={handleSelectNone}
className={cn(
"px-1 h-5 flex items-center gap-1 text-t3 text-xs hover:text-t1 hover:bg-accent cursor-pointer rounded-md",
@@ -181,112 +168,119 @@ export const ProductsSubMenu = () => {
"bg-primary/10 text-primary hover:text-primary/80",
)}
>
No products
No plans
</button>
</div>
<DropdownMenuSeparator />
<div className="max-h-64 overflow-y-auto">
{uniqueProducts?.map((product: any) => {
const versionCount = versionCounts?.[product.id] || 1;
const productVersionKeys = Array.from(
{ length: versionCount },
(_, i) => `${product.id}:${i + 1}`,
);
const allProductVersionsSelected = productVersionKeys.every((key) =>
selectedVersions.includes(key),
);
const someProductVersionsSelected = productVersionKeys.some((key) =>
selectedVersions.includes(key),
);
{uniqueProducts?.map((product: any) => {
const versionCount = versionCounts?.[product.id] || 1;
const productVersionKeys = Array.from(
{ length: versionCount },
(_, i) => `${product.id}:${i + 1}`,
);
const allProductVersionsSelected = productVersionKeys.every(
(key) => selectedVersions.includes(key),
);
const someProductVersionsSelected = productVersionKeys.some(
(key) => selectedVersions.includes(key),
);
return (
<div key={product.id}>
{versionCount === 1 ? (
// Single version - show just one button for the product
<DropdownMenuItem
onClick={(e) => {
e.preventDefault();
toggleVersion(product.id, "1");
}}
onSelect={(e) => e.preventDefault()}
className="flex items-center gap-2 cursor-pointer font-medium"
>
<Checkbox
checked={selectedVersions.includes(`${product.id}:1`)}
className="border-border"
/>
{product.name}
</DropdownMenuItem>
) : (
// Multiple versions - show product name with hover submenu for versions
<DropdownMenuSub>
<DropdownMenuSubTrigger
className="flex items-center gap-2 cursor-pointer font-medium"
onClick={(e) => {
e.preventDefault();
toggleProduct(product);
}}
>
<Checkbox
checked={allProductVersionsSelected}
className="border-border"
ref={(ref: any) => {
if (
ref &&
someProductVersionsSelected &&
!allProductVersionsSelected
) {
ref.indeterminate = true;
}
}}
/>
{product.name}
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
return (
<div key={product.id}>
{versionCount === 1 ? (
// Single version - show just one button for the product
<DropdownMenuItem
onClick={(e) => {
e.preventDefault();
toggleProduct(product);
toggleVersion(product.id, "1");
}}
onSelect={(e) => e.preventDefault()}
className="flex items-center gap-2 cursor-pointer font-medium"
>
<Checkbox checked={allProductVersionsSelected} className="border-border" />
All Versions
<Checkbox
checked={selectedVersions.includes(`${product.id}:1`)}
className="border-border"
/>
{product.name}
</DropdownMenuItem>
<DropdownMenuSeparator />
{Array.from(
{ length: versionCount },
(_, i) => i + 1,
).map((version) => {
const versionKey = `${product.id}:${version}`;
const isVersionSelected =
selectedVersions.includes(versionKey);
return (
) : (
// Multiple versions - show product name with hover submenu for versions
<DropdownMenuSub>
<DropdownMenuSubTrigger
className="flex items-center gap-2 cursor-pointer font-medium"
onClick={(e) => {
e.preventDefault();
toggleProduct(product);
}}
>
<Checkbox
checked={allProductVersionsSelected}
className="border-border"
ref={(ref: any) => {
if (
ref &&
someProductVersionsSelected &&
!allProductVersionsSelected
) {
ref.indeterminate = true;
}
}}
/>
{product.name}
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuItem
key={versionKey}
onClick={(e) => {
e.preventDefault();
toggleVersion(product.id, version.toString());
toggleProduct(product);
}}
onSelect={(e) => e.preventDefault()}
className="flex items-center gap-2 cursor-pointer text-sm"
className="flex items-center gap-2 cursor-pointer font-medium"
>
<Checkbox checked={isVersionSelected} className="border-border" />v{version}
<Checkbox
checked={allProductVersionsSelected}
className="border-border"
/>
All Versions
</DropdownMenuItem>
);
})}
</DropdownMenuSubContent>
</DropdownMenuSub>
)}
</div>
);
})}
</div>
</>
)}
<DropdownMenuSeparator />
{Array.from(
{ length: versionCount },
(_, i) => i + 1,
).map((version) => {
const versionKey = `${product.id}:${version}`;
const isVersionSelected =
selectedVersions.includes(versionKey);
return (
<DropdownMenuItem
key={versionKey}
onClick={(e) => {
e.preventDefault();
toggleVersion(product.id, version.toString());
}}
onSelect={(e) => e.preventDefault()}
className="flex items-center gap-2 cursor-pointer text-sm"
>
<Checkbox
checked={isVersionSelected}
className="border-border"
/>
v{version}
</DropdownMenuItem>
);
})}
</DropdownMenuSubContent>
</DropdownMenuSub>
)}
</div>
);
})}
</div>
</>
)}
</DropdownMenuSubContent>
</DropdownMenuSub>
);

View File

@@ -1,3 +1,7 @@
import { TrashIcon } from "@phosphor-icons/react";
import { useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
DropdownMenuGroup,
DropdownMenuItem,
@@ -9,13 +13,8 @@ import {
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { Button } from "@/components/ui/button";
import { toast } from "sonner";
import { getBackendErr } from "@/utils/genUtils";
import { useAxiosInstance } from "@/services/useAxiosInstance";
import { Delete } from "lucide-react";
import { useState } from "react";
import { getBackendErr } from "@/utils/genUtils";
import { useCustomersQueryStates } from "../../hooks/useCustomersQueryStates";
interface SavedView {
@@ -34,7 +33,7 @@ export const SavedViews = ({
mutateViews: any;
setDropdownOpen: (open: boolean) => void;
}) => {
const { setQueryStates } = useCustomersQueryStates();
const { setFilters } = useCustomersQueryStates();
const axiosInstance = useAxiosInstance();
const [deletingViewId, setDeletingViewId] = useState<string | null>(null);
@@ -44,24 +43,17 @@ export const SavedViews = ({
const decodedParams = atob(view.filters);
const params = new URLSearchParams(decodedParams);
// Apply all parameters using setQueryStates (this will reset pagination automatically)
// Apply all parameters using setFilters (this will reset pagination automatically)
const statusParam = params.get("status") || "";
const versionParam = params.get("version") || "";
const noneParam = params.get("none");
const queryParams = {
page: 1,
setFilters({
q: params.get("q") || "",
status: statusParam ? statusParam.split(",").filter(Boolean) : [],
version: versionParam ? versionParam.split(",").filter(Boolean) : [],
none: noneParam === "true",
lastItemId: "",
};
setQueryStates(queryParams);
// Explicitly trigger a data refetch to ensure the view is applied immediately
// await mutate();
});
toast.success(`Applied filters from ${view.name} view`);
} catch (error) {
@@ -95,7 +87,7 @@ export const SavedViews = ({
{views.map((view: SavedView) => (
<div
key={view.id}
className="flex items-center justify-between cursor-pointer px-2 hover:bg-zinc-100 rounded-sm"
className="flex items-center justify-between cursor-pointer px-2 hover:bg-accent rounded-sm"
onClick={async () => {
await applyView(view);
setDropdownOpen(false);
@@ -110,18 +102,22 @@ export const SavedViews = ({
<Popover>
<PopoverTrigger asChild>
<button
type="button"
onClick={(e) => {
e.stopPropagation();
}}
className="ml-2 p-1 hover:bg-zinc-200 rounded"
className="ml-2 p-1 hover:bg-destructive/10 rounded group"
>
<Delete size={12} className="text-t3" />
<TrashIcon
size={12}
className="text-t3 group-hover:text-red-500"
/>
</button>
</PopoverTrigger>
<PopoverContent
sideOffset={2}
align="start"
className="border border-zinc-200 w-64 z-50"
className="border w-64 z-200"
onOpenAutoFocus={(e) => e.preventDefault()}
onCloseAutoFocus={(e) => e.preventDefault()}
>

View File

@@ -1,3 +1,5 @@
import { BookmarkIcon, Trash2 } from "lucide-react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
@@ -10,8 +12,6 @@ import {
} from "@/components/ui/dropdown-menu";
import { useAxiosInstance } from "@/services/useAxiosInstance";
import { getBackendErr } from "@/utils/genUtils";
import { BookmarkIcon, Trash2 } from "lucide-react";
import { toast } from "sonner";
import { useCustomersQueryStates } from "../../hooks/useCustomersQueryStates";
import { useSavedViewsQuery } from "../../hooks/useSavedViewsQuery";
@@ -119,6 +119,7 @@ export const SavedViewsDropdown = () => {
>
<span className="truncate flex-1">{view.name}</span>
<button
type="button"
onClick={(e) => deleteView(view.id, view.name, e)}
className="ml-2 p-1 hover:bg-red-100 rounded"
>

View File

@@ -68,7 +68,7 @@ export const useAnalyticsData = ({
} = usePostSWR({
url: `/query/events`,
data: {
customer_id: customerId || null,
customer_id: customerId || undefined,
interval: interval || "30d",
event_names: [...(eventNames || []), ...(featureIds || [])],
group_by: formattedGroupBy,
@@ -132,7 +132,7 @@ export const useRawAnalyticsData = () => {
} = usePostSWR({
url: `/query/raw`,
data: {
customer_id: customerId || null,
customer_id: customerId || undefined,
interval: interval || "30d",
},
queryKey,

View File

@@ -6,7 +6,7 @@ import {
parseAsString,
useQueryStates,
} from "nuqs";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
export const useCustomersQueryStates = () => {
const [queryStates, setQueryStates] = useQueryStates(
{
@@ -22,7 +22,13 @@ export const useCustomersQueryStates = () => {
},
);
// return { queryStates, setQueryStates };
// Wrapper that resets pagination when filters change
const setFilters = useCallback(
(filters: Partial<Omit<typeof queryStates, "page" | "lastItemId">>) => {
setQueryStates({ ...filters, page: 1, lastItemId: "" });
},
[setQueryStates],
);
const [stableStates, setStableStates] = useState(queryStates);
@@ -33,5 +39,5 @@ export const useCustomersQueryStates = () => {
debouncedSetStableStates(queryStates);
}, [queryStates]);
return { queryStates: stableStates, setQueryStates };
return { queryStates: stableStates, setQueryStates, setFilters };
};

View File

@@ -275,6 +275,7 @@ export function SubscriptionDetailSheet() {
<CustomerProductsStatus
status={cusProduct.status}
canceled={cusProduct.canceled}
canceled_at={cusProduct.canceled_at ?? undefined}
trialing={
isCustomerProductTrialing(cusProduct, {
nowMs: Date.now(),

View File

@@ -91,6 +91,9 @@ const getCusProductsInfo = ({
canceled={
(cusProduct as FullCusProduct).canceled_at ? true : undefined
}
canceled_at={
(cusProduct as FullCusProduct).canceled_at ?? undefined
}
tooltip={true}
trialing={
isCustomerProductTrialing(cusProduct as FullCusProduct, {

View File

@@ -19,7 +19,7 @@ import { useCustomersQueryStates } from "@/views/customers/hooks/useCustomersQue
import { useSavedViewsQuery } from "@/views/customers/hooks/useSavedViewsQuery";
export function CustomerListFilterButton() {
const { setQueryStates } = useCustomersQueryStates();
const { setFilters } = useCustomersQueryStates();
const [open, setOpen] = useState(false);
const { data, refetch: refetchSavedViews } = useSavedViewsQuery();
@@ -27,11 +27,7 @@ export function CustomerListFilterButton() {
const views = data?.views || [];
const clearFilters = () => {
setQueryStates({
status: [],
version: [],
none: false,
});
setFilters({ status: [], version: [], none: false });
};
const closeFilterModal = () => {
@@ -51,7 +47,7 @@ export function CustomerListFilterButton() {
</IconButton>
</DropdownMenuTrigger>
<DropdownMenuContent
className="w-56 font-regular text-zinc-800 gap-0 p-0"
className="w-56 font-regular gap-0 p-0"
align="start"
>
<DropdownMenuGroup className="p-1">

View File

@@ -7,7 +7,7 @@ import { useCusSearchQuery } from "@/views/customers/hooks/useCusSearchQuery";
import { useCustomersQueryStates } from "@/views/customers/hooks/useCustomersQueryStates";
export function CustomerListSearchBar() {
const { queryStates, setQueryStates } = useCustomersQueryStates();
const { queryStates, setFilters } = useCustomersQueryStates();
const { totalCount } = useCusSearchQuery();
const navigate = useNavigate();
@@ -16,9 +16,9 @@ export function CustomerListSearchBar() {
const debouncedSearch = useMemo(
() =>
debounce(async (query: string) => {
setQueryStates({ q: query, page: 1 });
setFilters({ q: query });
}, 350),
[location.search, location.pathname, navigate, setQueryStates],
[location.search, location.pathname, navigate, setFilters],
);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {

View File

@@ -104,8 +104,14 @@ export function CustomerListTable({
const hasRows = table.getRowModel().rows.length > 0;
const hasSearchQuery = Boolean(queryStates.q?.trim());
const hasFilters =
queryStates.status.length > 0 ||
queryStates.version.length > 0 ||
queryStates.none;
const hasActiveFiltersOrSearch = hasSearchQuery || hasFilters;
if (!hasRows && !hasSearchQuery) {
// Only show empty state if org has NO customers (no filters/search active and no results)
if (!hasRows && !hasActiveFiltersOrSearch) {
return (
<EmptyState
type="customers"
@@ -142,7 +148,7 @@ export function CustomerListTable({
<CustomerListCreateButton />
</div>
{!hasRows && hasSearchQuery ? (
{!hasRows && hasActiveFiltersOrSearch ? (
<EmptyState
type="no-customers-found"
actionButton={<CustomerListCreateButton />}

View File

@@ -50,6 +50,7 @@ export const CustomerProductsColumns = [
status={row.original.status}
starts_at={row.original.starts_at ?? undefined}
canceled={row.original.canceled}
canceled_at={row.original.canceled_at ?? undefined}
trialing={isCustomerProductTrialing(row.original) || false}
trial_ends_at={row.original.trial_ends_at ?? undefined}
/>

View File

@@ -14,15 +14,29 @@ const StatusItem = ({
children,
text,
trial_ends_at,
canceled_at,
tooltip,
className,
}: {
children: React.ReactNode;
text: string;
trial_ends_at?: number;
canceled_at?: number;
tooltip?: boolean;
className?: string;
}) => {
const getSubtext = () => {
if (trial_ends_at) {
return `${formatDistanceToNow(trial_ends_at)} left`;
}
if (canceled_at) {
return `${formatDistanceToNow(canceled_at)} ago`;
}
return null;
};
const subtext = getSubtext();
return (
<div className={cn("flex items-center", className)}>
{tooltip ? (
@@ -31,10 +45,8 @@ const StatusItem = ({
<TooltipTrigger>{children}</TooltipTrigger>
<TooltipContent>
<span className="text-sm">{text} </span>
{trial_ends_at && (
<span className="text-sm text-t3">
({formatDistanceToNow(trial_ends_at)} left)
</span>
{subtext && (
<span className="text-sm text-t3">({subtext})</span>
)}
</TooltipContent>
</Tooltip>
@@ -45,12 +57,10 @@ const StatusItem = ({
{children}
<span className="text-sm">{text}</span>
</div>
{trial_ends_at && (
{subtext && (
<>
<DotIcon size={16} />
<span className="text-sm text-t3 pl-1 truncate">
{formatDistanceToNow(trial_ends_at)} left
</span>
<span className="text-sm text-t3 pl-1 truncate">{subtext}</span>
</>
)}
</>
@@ -63,6 +73,7 @@ export const CustomerProductsStatus = ({
tooltip,
status,
canceled,
canceled_at,
trialing,
trial_ends_at,
starts_at,
@@ -70,6 +81,7 @@ export const CustomerProductsStatus = ({
status?: CusProductStatus;
tooltip?: boolean;
canceled?: boolean;
canceled_at?: number;
trialing?: boolean;
trial_ends_at?: number;
starts_at?: number;
@@ -105,7 +117,7 @@ export const CustomerProductsStatus = ({
// If product is canceled, show that status
if (canceled) {
return (
<StatusItem text="Cancelling" tooltip={tooltip}>
<StatusItem text="Cancelling" tooltip={tooltip} canceled_at={canceled_at}>
<BanIcon
className="text-white bg-orange-500 dark:bg-orange-600 rounded-full p-0.5"
size={12}

View File

@@ -152,7 +152,7 @@ export const MainSidebar = () => {
icon: <CubeIcon size={16} weight="fill" />,
},
{
title: "Features",
title: "Plan Features",
value: "features",
icon: <LegoIcon size={16} weight="fill" />,
},

View File

@@ -105,9 +105,9 @@ function StepCard({
animate={{ flex: isActive ? 4 : 1 }}
transition={{ duration: 0.3, ease: "easeInOut" }}
className={cn(
"relative rounded-xl border bg-card cursor-pointer h-29 overflow-hidden",
"relative border dark:border-none rounded-xl bg-card cursor-pointer h-29 overflow-hidden",
isActive
? "border-primary/30"
? ""
: "hover:border-primary/20 hover:bg-interactive-secondary-hover",
isComplete && !isActive && "opacity-50",
)}

View File

@@ -22,12 +22,14 @@ interface UpdateFeatureSheetProps {
open: boolean;
setOpen: (open: boolean) => void;
selectedFeature: Feature | null;
onSuccess?: (oldId: string, newId: string) => void;
}
function UpdateFeatureSheet({
open,
setOpen,
selectedFeature,
onSuccess,
}: UpdateFeatureSheetProps) {
const [loading, setLoading] = useState(false);
@@ -63,6 +65,12 @@ function UpdateFeatureSheet({
await refetch();
toast.success("Feature updated successfully");
// Call onSuccess with old and new IDs, if it's updated from the plan editor to update the plan items.
if (onSuccess) {
onSuccess(selectedFeature.id, feature.id);
}
setOpen(false);
} catch (error: unknown) {
console.log(error);

View File

@@ -21,12 +21,14 @@ interface UpdateCreditSystemSheetProps {
open: boolean;
setOpen: (open: boolean) => void;
selectedCreditSystem: Feature | null;
onSuccess?: (oldId: string, newId: string) => void;
}
function UpdateCreditSystemSheet({
open,
setOpen,
selectedCreditSystem,
onSuccess,
}: UpdateCreditSystemSheetProps) {
const [loading, setLoading] = useState(false);
const [creditSystem, setCreditSystem] = useState<CreateFeature>({
@@ -92,6 +94,12 @@ function UpdateCreditSystemSheet({
await refetch();
toast.success("Credit system updated successfully");
// Call onSuccess with old and new IDs
if (onSuccess) {
onSuccess(selectedCreditSystem.id, creditSystem.id || selectedCreditSystem.id);
}
setOpen(false);
} catch (error: unknown) {
console.log(error);

View File

@@ -1,10 +1,6 @@
import { AnimatePresence, motion } from "motion/react";
import { createPortal } from "react-dom";
import {
useCurrentItem,
useHasItemChanges,
useIsCusPlanEditor,
} from "@/hooks/stores/useProductStore";
import { motion } from "motion/react";
import { SheetOverlay } from "@/components/v2/sheet-overlay/SheetOverlay";
import { useIsCusPlanEditor } from "@/hooks/stores/useProductStore";
import { useSheetStore } from "@/hooks/stores/useSheetStore";
import { CustomerPlanEditorBar } from "@/views/customers2/customer-plan/CustomerPlanEditorBar";
import { CustomerPlanInfoBox } from "@/views/customers2/customer-plan/CustomerPlanInfoBox";
@@ -14,66 +10,8 @@ import { EditPlanHeader } from "./EditPlanHeader";
import PlanCard from "./plan-card/PlanCard";
import { SaveChangesBar } from "./SaveChangesBar";
function shouldCloseSheetOnMouseDown({
e,
item,
sheetType,
hasItemChanges,
}: {
e: React.MouseEvent<HTMLDivElement>;
item: ReturnType<typeof useCurrentItem>;
sheetType: string | null;
hasItemChanges: boolean;
}): boolean {
// Don't close if item has unsaved changes
if (hasItemChanges) {
return false;
}
// Don't close if item is invalid
// if (item && !checkItemIsValid(item, false)) {
// return false;
// }
// Get the active element before blur happens
const activeElement = document.activeElement;
if (
activeElement &&
activeElement !== document.body &&
activeElement instanceof HTMLElement
) {
// Only apply blur behavior to inputs, textareas, and selects
const isInputElement =
activeElement.tagName === "INPUT" ||
activeElement.tagName === "TEXTAREA" ||
activeElement.tagName === "SELECT";
if (!isInputElement) {
// Not an input, proceed with normal close behavior
return !!sheetType;
}
// Check if the active element is within the sheet (not in the main content area)
const clickTarget = e.target as HTMLElement;
const isActiveInSheet = !clickTarget.contains(activeElement);
if (isActiveInSheet) {
activeElement.blur();
e.preventDefault(); // Prevent default to stop the click from propagating
return false;
}
}
// If the click is outside the sheet and no input is focused, close the sheet
return !!sheetType;
}
export const PlanEditor = () => {
const closeSheet = useSheetStore((s) => s.closeSheet);
const sheetType = useSheetStore((s) => s.type);
const item = useCurrentItem();
const hasItemChanges = useHasItemChanges();
return (
<div className="flex w-full h-full overflow-hidden relative">
@@ -100,32 +38,7 @@ export const PlanEditor = () => {
)}
</div>
</div>
{createPortal(
<AnimatePresence>
{sheetType && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 bg-white/70 dark:bg-black/70"
style={{ zIndex: 40 }}
onMouseDown={(e) => {
if (
shouldCloseSheetOnMouseDown({
e,
item,
sheetType,
hasItemChanges,
})
) {
closeSheet();
}
}}
/>
)}
</AnimatePresence>,
document.body,
)}
<SheetOverlay />
</motion.div>
<ProductSheets />

View File

@@ -128,9 +128,9 @@ export const SaveChangesBar = ({
<p className="text-body whitespace-nowrap truncate">
You have unsaved changes
</p>
<Button variant="secondary" onClick={handleDiscardClicked}>
Discard
</Button>
<Button variant="secondary" onClick={handleDiscardClicked} disabled={saving}>
Discard
</Button>
<ShortcutButton
metaShortcut="s"
onClick={handleSaveClicked}

View File

@@ -1,12 +1,18 @@
import { FeatureType } from "@autumn/shared";
import { PencilSimpleIcon } from "@phosphor-icons/react";
import { useState } from "react";
import { IconButton } from "@/components/v2/buttons/IconButton";
import {
useHasItemChanges,
useProduct,
useSheet,
} from "@/components/v2/inline-custom-plan-editor/PlanEditorContext";
import { SheetHeader, SheetSection } from "@/components/v2/sheets/InlineSheet";
import { useFeaturesQuery } from "@/hooks/queries/useFeaturesQuery";
import { getFeature } from "@/utils/product/entitlementUtils";
import { isFeaturePriceItem } from "@/utils/product/getItemType";
import UpdateFeatureSheet from "@/views/products/features/components/UpdateFeatureSheet";
import UpdateCreditSystemSheet from "@/views/products/features/credit-systems/components/UpdateCreditSystemSheet";
import { useProductItemContext } from "@/views/products/product/product-item/ProductItemContext";
import { AdvancedSettings } from "./AdvancedSettings";
import { BillingType } from "./BillingType";
@@ -22,9 +28,28 @@ export function EditPlanFeatureSheet({
isOnboarding?: boolean;
}) {
const { item } = useProductItemContext();
const { features } = useFeaturesQuery();
const { product } = useProduct();
const { features, refetch } = useFeaturesQuery();
const { product, setProduct } = useProduct();
const { setInitialItem } = useSheet();
const hasItemChanges = useHasItemChanges();
const [editFeatureOpen, setEditFeatureOpen] = useState(false);
const handleFeatureUpdateSuccess = async (oldId: string, newId: string) => {
if (oldId !== newId && product.items) {
// Wait for features to be refetched to avoid race condition
await refetch();
// Update the feature_id in the product item
const updatedItems = product.items.map((i) =>
i.feature_id === oldId ? { ...i, feature_id: newId } : i,
);
setProduct({ ...product, items: updatedItems });
// Also update initialItem so it doesn't show as having changes
if (item?.feature_id === oldId) {
setInitialItem({ ...item, feature_id: newId });
}
}
};
const emptyPriceItem =
item?.usage_model &&
@@ -56,6 +81,16 @@ export function EditPlanFeatureSheet({
<span className="font-medium text-t1">{feature?.name}</span>
</p>
}
action={
<IconButton
variant="muted"
size="sm"
icon={<PencilSimpleIcon />}
onClick={() => setEditFeatureOpen(true)}
>
Edit Feature
</IconButton>
}
/>
)}
@@ -98,6 +133,23 @@ export function EditPlanFeatureSheet({
{/* Footer stays at bottom */}
{showFooter && <SheetFooterActions />}
{/* Edit Feature Sheet */}
{feature?.type === FeatureType.CreditSystem ? (
<UpdateCreditSystemSheet
open={editFeatureOpen}
setOpen={setEditFeatureOpen}
selectedCreditSystem={feature ?? null}
onSuccess={handleFeatureUpdateSuccess}
/>
) : (
<UpdateFeatureSheet
open={editFeatureOpen}
setOpen={setEditFeatureOpen}
selectedFeature={feature ?? null}
onSuccess={handleFeatureUpdateSuccess}
/>
)}
</div>
);
}

View File

@@ -16,22 +16,27 @@ export const getDefaultItem = ({
feature,
});
// For static (boolean) features, reset_usage_when_enabled is not applicable
// since they don't track usage. Setting it causes mismatch with backend
// which doesn't store this field for boolean features.
const isStaticFeature = itemFeatureType === ProductItemFeatureType.Static;
const isContinuousUse =
itemFeatureType === ProductItemFeatureType.ContinuousUse;
// Create a new item with the selected feature
const newItem = {
feature_id: feature.id,
feature_type: itemFeatureType,
included_usage: null,
interval:
itemFeatureType === ProductItemFeatureType.ContinuousUse ||
itemFeatureType === ProductItemFeatureType.Static
? null
: ProductItemInterval.Month,
isContinuousUse || isStaticFeature ? null : ProductItemInterval.Month,
price: null,
tiers: null,
billing_units: 1,
entity_feature_id: null,
reset_usage_when_enabled:
itemFeatureType !== ProductItemFeatureType.ContinuousUse,
// Only set reset_usage_when_enabled for usage-tracked features
// Boolean/static features don't track usage, so this field is not applicable
reset_usage_when_enabled: isStaticFeature ? undefined : !isContinuousUse,
};
return newItem;

View File

@@ -17,7 +17,7 @@ export const createProductListColumns = ({
size: 300,
header: "Name",
accessorKey: "name",
enableSorting: false,
enableSorting: true,
cell: ({ row }: { row: Row<ProductV2> }) => {
return (
<div className="font-medium text-t1 flex gap-1">

View File

@@ -1,6 +1,7 @@
import { isOneOffProductV2, type ProductV2 } from "@autumn/shared";
import { CubeIcon } from "@phosphor-icons/react";
import { useMemo } from "react";
import type { SortingState } from "@tanstack/react-table";
import { useMemo, useState } from "react";
import { Table } from "@/components/general/table";
import { SectionTag } from "@/components/v2/badges/SectionTag";
import { EmptyState } from "@/components/v2/empty-states/EmptyState";
@@ -20,6 +21,9 @@ export function ProductListTable() {
const { products, counts, isCountsLoading } = useProductsQuery();
const { queryStates } = useProductsQueryState();
// Shared sorting state for all tables
const [sorting, setSorting] = useState<SortingState>([]);
const { recurringBasePlans, recurringAddOnPlans, oneTimePlans } =
useMemo(() => {
const filtered = products?.filter((product) =>
@@ -100,6 +104,8 @@ export function ProductListTable() {
globalFilterFn: "includesString",
enableGlobalFilter: true,
enableSorting: true,
state: { sorting },
onSortingChange: setSorting,
},
});
@@ -110,6 +116,8 @@ export function ProductListTable() {
globalFilterFn: "includesString",
enableGlobalFilter: true,
enableSorting: true,
state: { sorting },
onSortingChange: setSorting,
},
});
@@ -120,6 +128,8 @@ export function ProductListTable() {
globalFilterFn: "includesString",
enableGlobalFilter: true,
enableSorting: true,
state: { sorting },
onSortingChange: setSorting,
},
});