fix: sample app

This commit is contained in:
John Yeo
2025-10-21 11:26:19 +01:00
parent ddf07b0ed0
commit 4687022e7d
10 changed files with 56 additions and 47 deletions

View File

@@ -142,6 +142,7 @@ export const productsAreSame = ({
item1: item, item1: item,
item2: similarItem!, item2: similarItem!,
features, features,
logDifferences: false,
}); });
if (!same) { if (!same) {

View File

@@ -105,9 +105,11 @@ const tiersAreSame = (
export const featureItemsAreSame = ({ export const featureItemsAreSame = ({
item1, item1,
item2, item2,
logDifferences = false,
}: { }: {
item1: FeatureItem; item1: FeatureItem;
item2: FeatureItem; item2: FeatureItem;
logDifferences?: boolean;
}) => { }) => {
const checks = { const checks = {
feature_id: { feature_id: {
@@ -135,15 +137,22 @@ export const featureItemsAreSame = ({
item1.reset_usage_when_enabled == item2.reset_usage_when_enabled, item1.reset_usage_when_enabled == item2.reset_usage_when_enabled,
message: `Reset usage when enabled different: ${item1.reset_usage_when_enabled} !== ${item2.reset_usage_when_enabled}`, message: `Reset usage when enabled different: ${item1.reset_usage_when_enabled} !== ${item2.reset_usage_when_enabled}`,
}, },
config: { rollover_config: {
condition: JSON.stringify(item1.config) === JSON.stringify(item2.config), condition: rolloversAreSame({
message: `Config different: ${JSON.stringify(item1.config)} !== ${JSON.stringify(item2.config)}`, rollover1: item1.config?.rollover || undefined,
rollover2: item2.config?.rollover || undefined,
}),
message: `Rollover config different: ${JSON.stringify(item1.config?.rollover)} !== ${JSON.stringify(item2.config?.rollover)}`,
}, },
// config: {
// condition: JSON.stringify(item1.config) === JSON.stringify(item2.config),
// message: `Config different: ${JSON.stringify(item1.config)} !== ${JSON.stringify(item2.config)}`,
// },
}; };
const same = Object.values(checks).every((d) => d.condition); const same = Object.values(checks).every((d) => d.condition);
if (!same) { if (!same && logDifferences) {
console.log( console.log(
"Feature items different:", "Feature items different:",
Object.values(checks) Object.values(checks)
@@ -158,16 +167,18 @@ export const featureItemsAreSame = ({
export const priceItemsAreSame = ({ export const priceItemsAreSame = ({
item1, item1,
item2, item2,
logDifferences = false,
}: { }: {
item1: PriceItem; item1: PriceItem;
item2: PriceItem; item2: PriceItem;
logDifferences?: boolean;
}) => { }) => {
const same = const same =
item1.price === item2.price && item1.price === item2.price &&
item1.interval == item2.interval && item1.interval == item2.interval &&
(item1.interval_count || 1) == (item2.interval_count || 1); (item1.interval_count || 1) == (item2.interval_count || 1);
if (!same) { if (!same && logDifferences) {
console.log(`Price items different: ${item1.price}`); console.log(`Price items different: ${item1.price}`);
} }
@@ -210,9 +221,11 @@ const rolloversAreSame = ({
export const featurePriceItemsAreSame = ({ export const featurePriceItemsAreSame = ({
item1, item1,
item2, item2,
logDifferences = false,
}: { }: {
item1: FeaturePriceItem; item1: FeaturePriceItem;
item2: FeaturePriceItem; item2: FeaturePriceItem;
logDifferences?: boolean;
}) => { }) => {
// console.log("Item 1 config:", item1.config); // console.log("Item 1 config:", item1.config);
// console.log("Item 2 config:", item2.config); // console.log("Item 2 config:", item2.config);
@@ -297,7 +310,7 @@ export const featurePriceItemsAreSame = ({
const pricesChanged = Object.values(pricesSame).some((d) => !d.condition); const pricesChanged = Object.values(pricesSame).some((d) => !d.condition);
if (!same) { if (!same && logDifferences) {
console.log( console.log(
"Feature price items different:", "Feature price items different:",
Object.values(entsSame) Object.values(entsSame)
@@ -319,10 +332,12 @@ export const itemsAreSame = ({
item1, item1,
item2, item2,
features, features,
logDifferences = false,
}: { }: {
item1: ProductItem; item1: ProductItem;
item2: ProductItem; item2: ProductItem;
features?: Feature[]; features?: Feature[];
logDifferences?: boolean;
}) => { }) => {
// 1. If feature item // 1. If feature item
let same = false; let same = false;
@@ -339,6 +354,7 @@ export const itemsAreSame = ({
same = featureItemsAreSame({ same = featureItemsAreSame({
item1: item1 as FeatureItem, item1: item1 as FeatureItem,
item2: item2 as FeatureItem, item2: item2 as FeatureItem,
logDifferences,
}); });
pricesChanged = false; pricesChanged = false;
@@ -356,6 +372,7 @@ export const itemsAreSame = ({
featurePriceItemsAreSame({ featurePriceItemsAreSame({
item1: item1 as FeaturePriceItem, item1: item1 as FeaturePriceItem,
item2: item2 as FeaturePriceItem, item2: item2 as FeaturePriceItem,
logDifferences,
}); });
same = same_; same = same_;
@@ -377,6 +394,7 @@ export const itemsAreSame = ({
same = priceItemsAreSame({ same = priceItemsAreSame({
item1: item1 as PriceItem, item1: item1 as PriceItem,
item2: item2 as PriceItem, item2: item2 as PriceItem,
logDifferences,
}); });
if (!same) { if (!same) {
pricesChanged = true; pricesChanged = true;

View File

@@ -190,6 +190,7 @@ export const productsAreSame = ({
item1: item, item1: item,
item2: similarItem, item2: similarItem,
features, features,
logDifferences: false,
}); });
if (!same) { if (!same) {

View File

@@ -73,7 +73,7 @@ export default function PricingTablePreview({
} else if (productCount === 2) { } else if (productCount === 2) {
return "flex flex-col gap-6 max-w-2xl mx-auto px-4 sm:grid sm:grid-cols-2 sm:flex-none"; // Vertical on mobile, 2 columns on sm+ return "flex flex-col gap-6 max-w-2xl mx-auto px-4 sm:grid sm:grid-cols-2 sm:flex-none"; // Vertical on mobile, 2 columns on sm+
} else { } else {
return "flex flex-col gap-6 max-w-7xl mx-auto px-4 sm:grid md:grid-cols-2 xl:grid-cols-3 sm:flex-none"; // Vertical on mobile, 2 columns on sm+, 3 on lg+ return "flex flex-col gap-6 max-w-7xl mx-auto px-4 sm:grid lg:grid-cols-2 2xl:grid-cols-3 sm:flex-none"; // Vertical on mobile, 2 columns on sm+, 3 on lg+
} }
}; };

View File

@@ -33,8 +33,10 @@ export const OnboardingStepRenderer = () => {
const setProduct = useProductStore((s) => s.setProduct); const setProduct = useProductStore((s) => s.setProduct);
const sheetType = useSheetStore((s) => s.type); const sheetType = useSheetStore((s) => s.type);
const itemId = useSheetStore((s) => s.itemId); const itemId = useSheetStore((s) => s.itemId);
const [trackResponse, setTrackResponse] = useState<any>(null); const [trackResponse, setTrackResponse] = useState<any>(null);
const [checkResponse, setCheckResponse] = useState<any>(null); const [checkResponse, setCheckResponse] = useState<any>(null);
const [lastUsedFeatureId, setLastUsedFeatureId] = useState< const [lastUsedFeatureId, setLastUsedFeatureId] = useState<
string | undefined string | undefined
>(undefined); >(undefined);

View File

@@ -1,6 +1,6 @@
import { FeatureType } from "@autumn/shared"; import { FeatureType } from "@autumn/shared";
import { ArrowRightIcon } from "@phosphor-icons/react"; import { ArrowRightIcon } from "@phosphor-icons/react";
import { useCustomer } from "autumn-js/react"; import { PaywallDialog, useCustomer } from "autumn-js/react";
import { useState } from "react"; import { useState } from "react";
import { Button } from "@/components/v2/buttons/Button"; import { Button } from "@/components/v2/buttons/Button";
import { Input } from "@/components/v2/inputs/Input"; import { Input } from "@/components/v2/inputs/Input";
@@ -104,11 +104,11 @@ export const AvailableFeatures = ({
const featureId = customer?.features[x].id; const featureId = customer?.features[x].id;
// Check the feature access // Check the feature access
const { data: checkResponse, error: checkError } = const { data: checkResponse, error: checkError } = check({
await check({ featureId: featureId,
featureId: featureId, requiredBalance: value,
requiredBalance: value, dialog: PaywallDialog,
}); });
if (!checkError && checkResponse && onCheckSuccess) { if (!checkError && checkResponse && onCheckSuccess) {
onCheckSuccess(checkResponse); onCheckSuccess(checkResponse);
@@ -118,6 +118,8 @@ export const AvailableFeatures = ({
onFeatureUsed(featureId); onFeatureUsed(featureId);
} }
if (!checkResponse?.allowed) return;
// Track the usage // Track the usage
const { data, error } = await track({ const { data, error } = await track({
featureId: featureId, featureId: featureId,
@@ -135,8 +137,8 @@ export const AvailableFeatures = ({
)) ))
) : ( ) : (
<span className="text-sm text-muted-foreground"> <span className="text-sm text-muted-foreground">
Your current plan doesn't have any features. Try purchasing a Your current plan doesn't have any features. Try purchasing a plan
plan in the preview first. in the preview first.
</span> </span>
)} )}
</div> </div>

View File

@@ -152,10 +152,7 @@ export const QuickStartCodeGroup = ({
snippets={snippets.track} snippets={snippets.track}
trackResponse={trackResponse} trackResponse={trackResponse}
/> />
<CodeSnippetSection <CodeSnippetSection title="Checkout" snippets={snippets.checkout} />
title="Create checkout session"
snippets={snippets.checkout}
/>
<CustomerSection /> <CustomerSection />
</div> </div>
</SheetSection> </SheetSection>

View File

@@ -11,10 +11,14 @@ export const getCodeSnippets = (
allowed: { allowed: {
react: `import { useCustomer } from 'autumn-js/react'; react: `import { useCustomer } from 'autumn-js/react';
const { allowed } = useCustomer(); const { check } = useCustomer();
const handleCheckFeature = async () => { const handleCheckFeature = async () => {
if ( !allowed({ featureId: '${actualFeatureId}' }) ) { const { data } = await check({
featureId: '${actualFeatureId}',
requiredQuantity: 1
});
if (!data?.allowed) {
alert('Feature not allowed'); alert('Feature not allowed');
} }
}`, }`,
@@ -24,7 +28,7 @@ const autumn = new Autumn({
apiKey: process.env.AUTUMN_API_KEY apiKey: process.env.AUTUMN_API_KEY
}); });
const allowed = await autumn.check({ const { data, error } = await autumn.check({
customerId: 'cust_123', customerId: 'cust_123',
featureId: '${actualFeatureId}' featureId: '${actualFeatureId}'
});`, });`,

View File

@@ -2,7 +2,6 @@ import { UserIcon } from "@phosphor-icons/react";
import { useState } from "react"; import { useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { AdminHover } from "@/components/general/AdminHover"; import { AdminHover } from "@/components/general/AdminHover";
import { Badge } from "@/components/v2/badges/Badge";
import { IconBadge } from "@/components/v2/badges/IconBadge"; import { IconBadge } from "@/components/v2/badges/IconBadge";
import V2Breadcrumb from "@/components/v2/breadcrumb"; import V2Breadcrumb from "@/components/v2/breadcrumb";
import { Button } from "@/components/v2/buttons/Button"; import { Button } from "@/components/v2/buttons/Button";
@@ -18,7 +17,6 @@ import { useSheetStore } from "@/hooks/stores/useSheetStore";
import { useAxiosInstance } from "@/services/useAxiosInstance"; import { useAxiosInstance } from "@/services/useAxiosInstance";
import { getBackendErr } from "@/utils/genUtils"; import { getBackendErr } from "@/utils/genUtils";
import { isOneOffProduct } from "@/utils/product/priceUtils"; import { isOneOffProduct } from "@/utils/product/priceUtils";
import { PlanTypeBadge } from "../../components/PlanTypeBadge";
import { useMigrationsQuery } from "../../product/hooks/queries/useMigrationsQuery.tsx.tsx"; import { useMigrationsQuery } from "../../product/hooks/queries/useMigrationsQuery.tsx.tsx";
import { useProductCountsQuery } from "../../product/hooks/queries/useProductCountsQuery"; import { useProductCountsQuery } from "../../product/hooks/queries/useProductCountsQuery";
import { import {
@@ -143,12 +141,12 @@ export const EditPlanHeader = () => {
size="sm" size="sm"
/> />
)} )}
{product.is_default && <Badge variant="muted">Default</Badge>} {/* {product.is_default && <Badge variant="muted">Default</Badge>}
{product.is_add_on && <Badge variant="muted">Add-on</Badge>} {product.is_add_on && <Badge variant="muted">Add-on</Badge>} */}
<IconBadge variant="muted" icon={<UserIcon />}> <IconBadge variant="muted" icon={<UserIcon />}>
{counts?.active || 0} {counts?.active || 0}
</IconBadge> </IconBadge>
<PlanTypeBadge product={product} /> {/* <PlanTypeBadge product={product} /> */}
<PlanToolbar /> <PlanToolbar />
</div> </div>

View File

@@ -52,28 +52,14 @@ export const PlanCardToolbar = ({
aria-label="Edit plan" aria-label="Edit plan"
variant="muted" variant="muted"
disabled={editDisabled} disabled={editDisabled}
size="sm" // size="sm"
className={cn(isEditingPlan && "btn-secondary-active !opacity-100 ")} className={cn(
// "text-body",
isEditingPlan && "btn-secondary-active !opacity-100 ",
)}
> >
Edit Details Plan Details
</IconButton> </IconButton>
{/* {product?.archived ? (
<Button variant="muted" onClick={() => setDeleteOpen(true)} size="sm">
Archived
</Button>
) : (
<IconButton
icon={<TrashIcon />}
onClick={() => setDeleteOpen(true)}
aria-label="Delete plan"
variant="muted"
iconOrientation="center"
disabled={deleteDisabled}
title={deleteDisabled && deleteTooltip ? deleteTooltip : undefined}
className={cn(deleteDisabled && "opacity-50 cursor-not-allowed")}
/>
)} */}
</div> </div>
</> </>
); );