diff --git a/app/(protected)/dashboard/urls/url-list.tsx b/app/(protected)/dashboard/urls/url-list.tsx index 36fde00..23fe985 100644 --- a/app/(protected)/dashboard/urls/url-list.tsx +++ b/app/(protected)/dashboard/urls/url-list.tsx @@ -64,8 +64,8 @@ export interface UrlListProps { function TableColumnSekleton() { return ( - - + + diff --git a/app/api/email/route.ts b/app/api/email/route.ts index 5332cec..8103c3b 100644 --- a/app/api/email/route.ts +++ b/app/api/email/route.ts @@ -4,6 +4,7 @@ import { createUserEmail, getAllUserEmails } from "@/lib/dto/email"; import { checkUserStatus } from "@/lib/dto/user"; import { reservedAddressSuffix } from "@/lib/enums"; import { getCurrentUser } from "@/lib/session"; +import { restrictByTimeRange, Team_Plan_Quota } from "@/lib/team"; // 查询所有 UserEmail 地址 export async function GET(req: NextRequest) { @@ -41,6 +42,16 @@ export async function POST(req: NextRequest) { const user = checkUserStatus(await getCurrentUser()); if (user instanceof Response) return user; + // check limit + const limit = await restrictByTimeRange({ + model: "userEmail", + userId: user.id, + limit: Team_Plan_Quota[user.team].EM_EmailAddresses, + rangeType: "month", + }); + if (limit.status !== 200) + return NextResponse.json(limit.statusText, { status: limit.status }); + const { emailAddress } = await req.json(); if (!emailAddress) { @@ -71,6 +82,7 @@ export async function POST(req: NextRequest) { status: 409, }); } + return NextResponse.json("Internal Server Error", { status: 500 }); } } diff --git a/app/api/email/send/route.ts b/app/api/email/send/route.ts index a3ee906..01023f3 100644 --- a/app/api/email/send/route.ts +++ b/app/api/email/send/route.ts @@ -4,7 +4,7 @@ import { getUserSendEmailCount, saveUserSendEmail } from "@/lib/dto/email"; import { checkUserStatus } from "@/lib/dto/user"; import { resend } from "@/lib/email"; import { getCurrentUser } from "@/lib/session"; -import { Team_Plan_Quota } from "@/lib/team"; +import { restrictByTimeRange, Team_Plan_Quota } from "@/lib/team"; import { isValidEmail } from "@/lib/utils"; export async function POST(req: NextRequest) { @@ -12,16 +12,15 @@ export async function POST(req: NextRequest) { const user = checkUserStatus(await getCurrentUser()); if (user instanceof Response) return user; - // check quota - const count = await getUserSendEmailCount(user.id, false); - if (count >= Team_Plan_Quota[user.team].EM_SendEmails) { - return Response.json( - `Your email addresses have reached the ${user.team} limit.`, - { - status: 409, - }, - ); - } + // check limit + const limit = await restrictByTimeRange({ + model: "userSendEmail", + userId: user.id, + limit: Team_Plan_Quota[user.team].EM_SendEmails, + rangeType: "month", + }); + if (limit.status !== 200) + return NextResponse.json(limit.statusText, { status: limit.status }); const { from, to, subject, html } = await req.json(); @@ -33,7 +32,7 @@ export async function POST(req: NextRequest) { return NextResponse.json("Invalid email address", { status: 403 }); } - const { data, error } = await resend.emails.send({ + const { error } = await resend.emails.send({ from, to, subject, diff --git a/app/api/url/add/route.ts b/app/api/url/add/route.ts index 5f097be..18c4b76 100644 --- a/app/api/url/add/route.ts +++ b/app/api/url/add/route.ts @@ -2,7 +2,7 @@ import { env } from "@/env.mjs"; import { createUserShortUrl, getUserShortUrlCount } from "@/lib/dto/short-urls"; import { checkUserStatus } from "@/lib/dto/user"; import { getCurrentUser } from "@/lib/session"; -import { Team_Plan_Quota } from "@/lib/team"; +import { restrictByTimeRange, Team_Plan_Quota } from "@/lib/team"; import { createUrlSchema } from "@/lib/validations/url"; export async function POST(req: Request) { @@ -10,13 +10,15 @@ export async function POST(req: Request) { const user = checkUserStatus(await getCurrentUser()); if (user instanceof Response) return user; - // check quota - const user_urls_count = await getUserShortUrlCount(user.id); - if (user_urls_count >= Team_Plan_Quota[user.team].SL_NewLinks) { - return Response.json("Your short urls have reached the free limit.", { - status: 409, - }); - } + // check limit + const limit = await restrictByTimeRange({ + model: "userUrl", + userId: user.id, + limit: Team_Plan_Quota[user.team].SL_NewLinks, + rangeType: "month", + }); + if (limit.status !== 200) + return Response.json(limit.statusText, { status: limit.status }); const { data } = await req.json(); diff --git a/app/api/v1/email/route.ts b/app/api/v1/email/route.ts index fbc3bf2..9dc5468 100644 --- a/app/api/v1/email/route.ts +++ b/app/api/v1/email/route.ts @@ -7,7 +7,7 @@ import { getAllUserEmailsCount, } from "@/lib/dto/email"; import { reservedAddressSuffix } from "@/lib/enums"; -import { Team_Plan_Quota } from "@/lib/team"; +import { restrictByTimeRange, Team_Plan_Quota } from "@/lib/team"; import { siteConfig } from "../../../../config/site"; @@ -35,15 +35,15 @@ export async function POST(req: NextRequest) { }); } - // check quota - const user_address_count = await getAllUserEmailsCount(user.id); - if ( - user_address_count >= Team_Plan_Quota[user.team || "free"].EM_EmailAddresses - ) { - return Response.json("Your email addresses have reached the free limit.", { - status: 403, - }); - } + // check limit + const limit = await restrictByTimeRange({ + model: "userEmail", + userId: user.id, + limit: Team_Plan_Quota[user.team!].EM_EmailAddresses, + rangeType: "month", + }); + if (limit.status !== 200) + return NextResponse.json(limit.statusText, { status: limit.status }); const { emailAddress } = await req.json(); diff --git a/app/api/v1/short/route.ts b/app/api/v1/short/route.ts index 0b86492..108b501 100644 --- a/app/api/v1/short/route.ts +++ b/app/api/v1/short/route.ts @@ -1,6 +1,6 @@ import { checkApiKey } from "@/lib/dto/api-key"; import { createUserShortUrl, getUserShortUrlCount } from "@/lib/dto/short-urls"; -import { Team_Plan_Quota } from "@/lib/team"; +import { restrictByTimeRange, Team_Plan_Quota } from "@/lib/team"; import { createUrlSchema } from "@/lib/validations/url"; export async function POST(req: Request) { @@ -21,13 +21,15 @@ export async function POST(req: Request) { ); } - // check quota - const user_urls_count = await getUserShortUrlCount(user.id); - if (user_urls_count >= Team_Plan_Quota[user.team || "free"].SL_NewLinks) { - return Response.json("Your short urls have reached the free limit.", { - status: 403, - }); - } + // check limit + const limit = await restrictByTimeRange({ + model: "userUrl", + userId: user.id, + limit: Team_Plan_Quota[user.team!].SL_NewLinks, + rangeType: "month", + }); + if (limit.status !== 200) + return Response.json(limit.statusText, { status: limit.status }); const data = await req.json(); diff --git a/components/email/EmailSidebar.tsx b/components/email/EmailSidebar.tsx index ab6c496..ec0d007 100644 --- a/components/email/EmailSidebar.tsx +++ b/components/email/EmailSidebar.tsx @@ -17,6 +17,7 @@ import useSWR from "swr"; import { siteConfig } from "@/config/site"; import { UserEmailList } from "@/lib/dto/email"; import { reservedAddressSuffix } from "@/lib/enums"; +import { Team_Plan_Quota } from "@/lib/team"; import { cn, fetcher, timeAgo } from "@/lib/utils"; import { useMediaQuery } from "@/hooks/use-media-query"; import ApiReference from "@/app/emails/api-reference"; @@ -349,6 +350,10 @@ export default function EmailSidebar({

+ {/* {" "} + + / {Team_Plan_Quota[user.team!].EM_SendEmails} + */}

diff --git a/components/sections/pricing.tsx b/components/sections/pricing.tsx index d935b93..ba6ddd6 100644 --- a/components/sections/pricing.tsx +++ b/components/sections/pricing.tsx @@ -5,11 +5,60 @@ import type { CSSProperties, ReactNode } from "react"; import { motion } from "framer-motion"; import { Check, X } from "lucide-react"; -import { cn } from "@/lib/utils"; +import { Team_Plan_Quota } from "@/lib/team"; +import { cn, nFormatter } from "@/lib/utils"; import { Icons } from "../shared/icons"; import { Button } from "../ui/button"; +const getBenefits = (plan) => [ + { + text: `${nFormatter(plan.SL_TrackedClicks)} tracked clicks/mo`, + checked: true, + icon: , + }, + { + text: `${nFormatter(plan.SL_NewLinks)} new links/mo`, + checked: true, + icon: , + }, + { + text: `${plan.SL_AnalyticsRetention}-day analytics retention`, + checked: true, + icon: , + }, + { + text: `${nFormatter(plan.EM_EmailAddresses)} email addresses/mo`, + checked: true, + icon: , // Updated icon to be more relevant + }, + { + text: `${nFormatter(plan.EM_SendEmails)} send emails/mo`, + checked: true, + icon: , // Updated icon to be more relevant + }, + { + text: `${plan.SL_Domains === 1 ? "One" : plan.SL_Domains} domain${plan.SL_Domains > 1 ? "s" : ""}`, + checked: true, + icon: , + }, + { + text: "Advanced analytics", + checked: plan.SL_AdvancedAnalytics, + icon: , + }, + { + text: `${plan.APP_Support.charAt(0).toUpperCase() + plan.APP_Support.slice(1)} support`, + checked: true, + icon: , + }, + { + text: "API Access", + checked: plan.APP_ApiAccess, + icon: , + }, +]; + export const PricingSection = () => { return (
@@ -25,7 +74,7 @@ export const PricingSection = () => {

-
+
{ Get started free } - benefits={[ - { - text: "100K tracked clicks", - checked: true, - icon: , - }, - { - text: "1k new links", - checked: true, - icon: , - }, - { - text: "180-day analytics retention", - checked: true, - icon: , - }, - { - text: "1k emails addresses", - checked: true, - icon: , - }, - { - text: "One domain", - checked: true, - icon: , - }, - { - text: "Advanced analytics", - checked: true, - icon: , - }, - { - text: "Basic support", - checked: true, - icon: , - }, - { - text: "API Access", - checked: true, - icon: , - }, - ]} + benefits={getBenefits(Team_Plan_Quota.free)} /> - {/* + } - benefits={[ - { text: "Five workspaces", checked: true }, - { text: "Email support", checked: true }, - { text: "7 day data retention", checked: true }, - { text: "Custom roles", checked: true }, - { text: "Priority support", checked: false }, - { text: "SSO", checked: false }, - ]} - /> */} + benefits={getBenefits(Team_Plan_Quota.premium)} + /> { Contact us } - benefits={[ - { - text: "Unlimited tracked clicks/mo", - checked: true, - icon: , - }, - { - text: "Unlimited new links", - checked: true, - icon: , - }, - { - text: "1-year analytics retention", - checked: true, - icon: , - }, - { - text: "1k emails addresses", - checked: true, - icon: , - }, - { - text: "Three domain", - checked: true, - icon: , - }, - { - text: "Advanced analytics", - checked: true, - icon: , - }, - { - text: "Basic support", - checked: true, - icon: , - }, - { - text: "API Access", - checked: true, - icon: , - }, - ]} + benefits={getBenefits(Team_Plan_Quota.business)} />
diff --git a/lib/team.ts b/lib/team.ts index b84087e..24479f9 100644 --- a/lib/team.ts +++ b/lib/team.ts @@ -1,26 +1,30 @@ +import { PrismaClient } from "@prisma/client"; + +import { prisma } from "./db"; + export const Team_Plan_Quota = { free: { SL_TrackedClicks: 100000, SL_NewLinks: 1000, SL_AnalyticsRetention: 180, - SL_Domains: 1, + SL_Domains: 2, SL_AdvancedAnalytics: true, RC_NewRecords: 0, EM_EmailAddresses: 1000, - EM_Domains: 1, - EM_SendEmails: 100, + EM_Domains: 2, + EM_SendEmails: 200, APP_Support: "basic", APP_ApiAccess: true, }, premium: { - SL_TrackedClicks: 10000000, - SL_NewLinks: 10000, + SL_TrackedClicks: 1000000, + SL_NewLinks: 5000, SL_AnalyticsRetention: 360, - SL_Domains: 3, + SL_Domains: 2, SL_AdvancedAnalytics: true, - RC_NewRecords: 3, - EM_EmailAddresses: 10000, - EM_Domains: 3, + RC_NewRecords: 2, + EM_EmailAddresses: 5000, + EM_Domains: 2, EM_SendEmails: 1000, APP_Support: "live", APP_ApiAccess: true, @@ -29,13 +33,88 @@ export const Team_Plan_Quota = { SL_TrackedClicks: 10000000, SL_NewLinks: 10000, SL_AnalyticsRetention: 360, - SL_Domains: 3, + SL_Domains: 2, SL_AdvancedAnalytics: true, - RC_NewRecords: 3, + RC_NewRecords: 2, EM_EmailAddresses: 10000, - EM_Domains: 3, - EM_SendEmails: 1000, + EM_Domains: 2, + EM_SendEmails: 2000, APP_Support: "live", APP_ApiAccess: true, }, }; + +type TimeRangeType = "day" | "month"; // 支持的限制周期 + +interface RestrictOptions { + model: keyof PrismaClient; // Prisma 模型名称,如 'userEmail' + userId: string; // 用户 ID + limit: number; // 限制数量 + rangeType: TimeRangeType; // 限制周期:'day' 或 'month' + referenceDate?: Date; // 可选,参考日期,默认为当前时间 +} + +/** + * 根据指定时间范围检查记录数量是否超过限制 + * @throws 如果超过限制,抛出错误 + */ +export async function restrictByTimeRange({ + model, + userId, + limit, + rangeType, + referenceDate, +}: RestrictOptions) { + const now = referenceDate || new Date(); + + let start: Date; + let end: Date; + + if (rangeType === "day") { + start = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + end = new Date( + now.getFullYear(), + now.getMonth(), + now.getDate(), + 23, + 59, + 59, + 999, + ); + } else if (rangeType === "month") { + start = new Date(now.getFullYear(), now.getMonth(), 1); + end = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59, 999); + } else { + return { + status: 400, + statusText: `Invalid range type: ${rangeType}`, + }; + } + + const modelInstance = prisma[model] as any; + + if (!modelInstance) { + return { + status: 400, + statusText: `Invalid model: ${model.toString()}`, + }; + } + + const count = await modelInstance.count({ + where: { + userId, + createdAt: { + gte: start, + lte: end, + }, + }, + }); + + if (count >= limit) { + return { + status: 409, + statusText: `You have exceeded the ${rangeType}ly ${model.toString()} creation limit (${limit}). Please try again later.`, + }; + } + return { status: 200 }; +} diff --git a/public/sw.js.map b/public/sw.js.map index c1f9ec4..32eeb12 100644 --- a/public/sw.js.map +++ b/public/sw.js.map @@ -1 +1 @@ -{"version":3,"file":"sw.js","sources":["../../../../../../private/var/folders/9b/3qmyp8zd2xvdspdrp149fyg00000gn/T/98412ccf39afa06d5c43cfd6a4f0a40b/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-routing@6.6.0/node_modules/workbox-routing/registerRoute.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-core@6.6.0/node_modules/workbox-core/clientsClaim.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\nimportScripts(\n \n);\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n\nworkbox_routing_registerRoute(\"/\", new workbox_strategies_NetworkFirst({ \"cacheName\":\"start-url\", plugins: [{ cacheWillUpdate: async ({ request, response, event, state }) => { if (response && response.type === 'opaqueredirect') { return new Response(response.body, { status: 200, statusText: 'OK', headers: response.headers }) } return response } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"sw.js","sources":["../../../../../../private/var/folders/9b/3qmyp8zd2xvdspdrp149fyg00000gn/T/b91d190853e86f19f3d0336ce4659ce6/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-routing@6.6.0/node_modules/workbox-routing/registerRoute.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-core@6.6.0/node_modules/workbox-core/clientsClaim.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\nimportScripts(\n \n);\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n\nworkbox_routing_registerRoute(\"/\", new workbox_strategies_NetworkFirst({ \"cacheName\":\"start-url\", plugins: [{ cacheWillUpdate: async ({ request, response, event, state }) => { if (response && response.type === 'opaqueredirect') { return new Response(response.body, { status: 200, statusText: 'OK', headers: response.headers }) } return response } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file