diff --git a/.vscode/settings.json b/.vscode/settings.json index c3a636c..c917da1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,9 +10,7 @@ "editor.defaultFormatter": "Prisma.prisma" }, // Class Variance Authority - "tailwindCSS.experimental.classRegex": [ - ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"] - ], + "tailwindCSS.experimental.classRegex": [["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]], "workbench.editor.labelFormat": "short", // Custom file nesting "explorer.fileNesting.enabled": true, @@ -25,7 +23,9 @@ }, // Override spellings in workspace "cSpell.words": [ + "AICOPY", "clsx", + "EXTRACOPY", "formik", "headlessui", "heroicons", diff --git a/migrate.mjs b/migrate.mjs new file mode 100644 index 0000000..ae3cabf --- /dev/null +++ b/migrate.mjs @@ -0,0 +1,31 @@ +import { Tier } from "tier"; + +export const tier = new Tier({ + baseURL: process.env.TIER_BASE_URL, + apiKey: process.env.TIER_API_KEY, + debug: true, +}); + +// Constants +const userId = "xxxxxxx"; // Fetch all users from your DB and loop through them +const featureName = "feature:aicopy"; // The feature where you want to migrate the usage +const newPlan = "plan:free@1"; // Your new plan + +const action = async () => { + const limits = await tier.lookupLimits(`org:${userId}`); + const freeFeatureUsage = limits.usage.find((_usage) => _usage.feature === featureName).used; + + await tier.subscribe(`org:${userId}`, newPlan); + await tier.report(`org:${userId}`, featureName, freeFeatureUsage); + + const updatedLimits = await tier.lookupLimits(`org:${userId}`); + return updatedLimits; +}; + +action() + .then((res) => { + console.log(res); + }) + .catch((err) => { + console.log(err); + }); diff --git a/next.config.mjs b/next.config.mjs index 3fd7ae2..9322944 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,4 +1,6 @@ -import "./src/env.mjs"; +// We ignore point 4 at https://env.t3.gg/docs/nextjs as env.mjs is now env.js +// env.mjs was renamed to env.js to remove any error caused while importing this to other modules in the project +// import "./src/env.mjs"; /** @type {import('next').NextConfig} */ const nextConfig = { diff --git a/pricing.json b/pricing.json deleted file mode 100644 index 06c6ffd..0000000 --- a/pricing.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "plans": { - "plan:free@0": { - "title": "Free", - "features": { - "feature:aicopy": { - "title": "1 AI generated copy", - "mode": "volume", - "tiers": [ - { - "upto": 1 - } - ] - }, - "feature:base": { - "base": 0, - "title": "Base" - } - } - }, - "plan:startup@0": { - "title": "Startup", - "features": { - "feature:aicopy": { - "title": "4 AI generated copy", - "mode": "volume", - "tiers": [ - { - "upto": 4 - } - ] - }, - "feature:base": { - "base": 2000, - "title": "Base" - }, - "feature:extraaicopy": { - "title": "Extras @ $5/copy", - "mode": "volume", - "tiers": [ - { - "price": 500 - } - ] - } - } - }, - "plan:business@0": { - "title": "Business", - "features": { - "feature:aicopy": { - "title": "10 AI generated copy", - "mode": "volume", - "tiers": [ - { - "upto": 10, - "base": 0 - } - ] - }, - "feature:base": { - "base": 4000, - "title": "Base" - }, - "feature:extraaicopy": { - "title": "Extras @ $4/copy", - "mode": "volume", - "tiers": [ - { - "price": 400 - } - ] - } - } - } - } -} diff --git a/src/app/(app)/billing/page.tsx b/src/app/(app)/billing/page.tsx index 7ed7140..ca8b531 100644 --- a/src/app/(app)/billing/page.tsx +++ b/src/app/(app)/billing/page.tsx @@ -1,7 +1,9 @@ import { Metadata } from "next"; import { clsx } from "clsx"; import type Stripe from "stripe"; +import type { CurrentPhase, LookupOrgResponse, PaymentMethodsResponse, Usage } from "tier"; +import { PricingTableData } from "@/types"; import { TIER_AICOPY_FEATURE_ID } from "@/config/tierConstants"; import { pullCurrentPlan } from "@/lib/services/currentPlan"; import { pullPricingTableData } from "@/lib/services/pricingTableData"; @@ -15,7 +17,6 @@ import { TierLogo } from "@/res/logos/TierLogo"; import { CheckoutButton } from "./CheckoutButton"; export const dynamic = "force-dynamic"; -export const revalidate = 0; export const metadata: Metadata = { title: "Billing", @@ -23,29 +24,26 @@ export const metadata: Metadata = { }; export default async function BillingPage() { - const pricing = await pullPricingTableData(); - const user = await getCurrentUser(); - // Fetch the feature consumption and limit of the AI copy feature for the plan currently subscribed - const featureLimits = await tier.lookupLimit(`org:${user?.id}`, TIER_AICOPY_FEATURE_ID); + let [pricing, featureLimits, phase, org, paymentMethodResponse] = await Promise.all([ + pullPricingTableData(), + // Fetch the feature consumption and limit of the AI copy feature for the plan currently subscribed + tier.lookupLimit(`org:${user?.id}`, TIER_AICOPY_FEATURE_ID), + // Fetch the phase data of the current subscription + tier.lookupPhase(`org:${user?.id}`), + // Fetch organization/user details + tier.lookupOrg(`org:${user?.id}`), + // Fetch the saved payment methods + tier.lookupPaymentMethods(`org:${user?.id}`), + ]); const usageLimit = featureLimits.limit; const used = featureLimits.used; - // Fetch the phase data of the current subscription - const phase = await tier.lookupPhase(`org:${user?.id}`); - console.log(phase.current?.end); - // Fetch the current plan from the pricing table data const currentPlan = await pullCurrentPlan(phase, pricing); - // Fetch organization/user details - const org = await tier.lookupOrg(`org:${user?.id}`); - - // Fetch the saved payment methods - const paymentMethodResponse = await tier.lookupPaymentMethods(`org:${user?.id}`); - const paymentMethod = paymentMethodResponse.methods[0] as unknown as Stripe.PaymentMethod; return ( diff --git a/src/app/(app)/generate/page.tsx b/src/app/(app)/generate/page.tsx index 4fde700..0963c00 100644 --- a/src/app/(app)/generate/page.tsx +++ b/src/app/(app)/generate/page.tsx @@ -6,7 +6,6 @@ import { tier } from "@/lib/tier"; import { Generate } from "@/components/app/GenerateSection"; export const dynamic = "force-dynamic"; -export const revalidate = 0; export const metadata: Metadata = { title: "Generate Copy", diff --git a/src/app/(app)/history/page.tsx b/src/app/(app)/history/page.tsx index 2098b3d..fb36698 100644 --- a/src/app/(app)/history/page.tsx +++ b/src/app/(app)/history/page.tsx @@ -5,7 +5,6 @@ import { getCurrentUser } from "@/lib/session"; import { Button } from "@/components/ui/Button"; export const dynamic = "force-dynamic"; -export const revalidate = 0; export const metadata: Metadata = { title: "History", diff --git a/src/app/(app)/layout.tsx b/src/app/(app)/layout.tsx index a63a1b4..7269f11 100644 --- a/src/app/(app)/layout.tsx +++ b/src/app/(app)/layout.tsx @@ -1,16 +1,21 @@ -import Link from "next/link"; - -import { Footer } from "@/components/Footer"; import { Header } from "@/components/app/Header"; +import { Footer } from "@/components/Footer"; interface AuthLayoutProps { children: React.ReactNode; } -export default function AppLayout({ children }: AuthLayoutProps) { +export default async function AppLayout({ children }: AuthLayoutProps) { + const res = await fetch("https://api.github.com/repos/tierrun/tier-vercel-openai", { + method: "GET", + next: { revalidate: 60 }, + }); + const data = await res.json(); + + const stargazers_count: number = data.stargazers_count; return ( <> -
+
{children}
diff --git a/src/app/(marketing)/layout.tsx b/src/app/(marketing)/layout.tsx index 2b1097c..b95b413 100644 --- a/src/app/(marketing)/layout.tsx +++ b/src/app/(marketing)/layout.tsx @@ -8,9 +8,18 @@ interface MarketingLayoutProps { } export default async function MarketingLayout({ children }: MarketingLayoutProps) { + const res = await fetch("https://api.github.com/repos/tierrun/tier-vercel-openai", { + method: "GET", + next: { revalidate: 60 }, + }); + const data = await res.json(); + + const stargazers_count: number = data.stargazers_count; + + console.log(data); return ( <> -
+
{children}