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 (
<>
-