@86d-store/memberships 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +193 -0
- package/dist/admin/components/_shared.d.ts +13 -0
- package/dist/admin/components/_shared.d.ts.map +1 -0
- package/dist/admin/components/_shared.js +17 -0
- package/dist/admin/components/membership-admin.d.ts +2 -0
- package/dist/admin/components/membership-admin.d.ts.map +1 -0
- package/dist/admin/components/membership-admin.js +47 -0
- package/dist/admin/components/membership-plans.d.ts +2 -0
- package/dist/admin/components/membership-plans.d.ts.map +1 -0
- package/dist/admin/components/membership-plans.js +153 -0
- package/dist/admin/endpoints/add-benefit.d.ts +28 -0
- package/dist/admin/endpoints/add-benefit.d.ts.map +1 -0
- package/dist/admin/endpoints/add-benefit.js +37 -0
- package/dist/admin/endpoints/cancel-membership.d.ts +16 -0
- package/dist/admin/endpoints/cancel-membership.d.ts.map +1 -0
- package/dist/admin/endpoints/cancel-membership.js +19 -0
- package/dist/admin/endpoints/create-plan.d.ts +29 -0
- package/dist/admin/endpoints/create-plan.d.ts.map +1 -0
- package/dist/admin/endpoints/create-plan.js +48 -0
- package/dist/admin/endpoints/delete-plan.d.ts +16 -0
- package/dist/admin/endpoints/delete-plan.d.ts.map +1 -0
- package/dist/admin/endpoints/delete-plan.js +14 -0
- package/dist/admin/endpoints/gate-product.d.ts +19 -0
- package/dist/admin/endpoints/gate-product.d.ts.map +1 -0
- package/dist/admin/endpoints/gate-product.js +25 -0
- package/dist/admin/endpoints/get-membership.d.ts +18 -0
- package/dist/admin/endpoints/get-membership.d.ts.map +1 -0
- package/dist/admin/endpoints/get-membership.js +15 -0
- package/dist/admin/endpoints/get-stats.d.ts +6 -0
- package/dist/admin/endpoints/get-stats.d.ts.map +1 -0
- package/dist/admin/endpoints/get-stats.js +7 -0
- package/dist/admin/endpoints/list-memberships.d.ts +20 -0
- package/dist/admin/endpoints/list-memberships.d.ts.map +1 -0
- package/dist/admin/endpoints/list-memberships.js +32 -0
- package/dist/admin/endpoints/list-plans.d.ts +16 -0
- package/dist/admin/endpoints/list-plans.d.ts.map +1 -0
- package/dist/admin/endpoints/list-plans.js +29 -0
- package/dist/admin/endpoints/pause-membership.d.ts +16 -0
- package/dist/admin/endpoints/pause-membership.d.ts.map +1 -0
- package/dist/admin/endpoints/pause-membership.js +19 -0
- package/dist/admin/endpoints/remove-benefit.d.ts +16 -0
- package/dist/admin/endpoints/remove-benefit.d.ts.map +1 -0
- package/dist/admin/endpoints/remove-benefit.js +14 -0
- package/dist/admin/endpoints/resume-membership.d.ts +16 -0
- package/dist/admin/endpoints/resume-membership.d.ts.map +1 -0
- package/dist/admin/endpoints/resume-membership.js +19 -0
- package/dist/admin/endpoints/routes.d.ts +237 -0
- package/dist/admin/endpoints/routes.d.ts.map +1 -0
- package/dist/admin/endpoints/routes.js +30 -0
- package/dist/admin/endpoints/ungate-product.d.ts +13 -0
- package/dist/admin/endpoints/ungate-product.d.ts.map +1 -0
- package/dist/admin/endpoints/ungate-product.js +22 -0
- package/dist/admin/endpoints/update-plan.d.ts +32 -0
- package/dist/admin/endpoints/update-plan.d.ts.map +1 -0
- package/dist/admin/endpoints/update-plan.js +62 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +75 -0
- package/dist/schema.d.ts +102 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +63 -0
- package/dist/service-impl.d.ts +4 -0
- package/dist/service-impl.d.ts.map +1 -0
- package/dist/service-impl.js +414 -0
- package/dist/service.d.ts +145 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +1 -0
- package/dist/store/components/_hooks.d.ts +9 -0
- package/dist/store/components/_hooks.d.ts.map +1 -0
- package/dist/store/components/_hooks.js +13 -0
- package/dist/store/components/_utils.d.ts +11 -0
- package/dist/store/components/_utils.d.ts.map +1 -0
- package/dist/store/components/_utils.js +98 -0
- package/dist/store/components/mdx.d.ts +10 -0
- package/dist/store/components/mdx.d.ts.map +1 -0
- package/dist/store/components/mdx.js +9 -0
- package/dist/store/components/my-membership.d.ts +2 -0
- package/dist/store/components/my-membership.d.ts.map +1 -0
- package/dist/store/components/my-membership.js +42 -0
- package/dist/store/components/my-membership.mdx +13 -0
- package/dist/store/components/plan-detail.d.ts +5 -0
- package/dist/store/components/plan-detail.d.ts.map +1 -0
- package/dist/store/components/plan-detail.js +50 -0
- package/dist/store/components/plan-detail.mdx +15 -0
- package/dist/store/components/plan-listing.d.ts +2 -0
- package/dist/store/components/plan-listing.d.ts.map +1 -0
- package/dist/store/components/plan-listing.js +21 -0
- package/dist/store/components/plan-listing.mdx +13 -0
- package/dist/store/endpoints/cancel.d.ts +16 -0
- package/dist/store/endpoints/cancel.d.ts.map +1 -0
- package/dist/store/endpoints/cancel.js +25 -0
- package/dist/store/endpoints/check-access.d.ts +10 -0
- package/dist/store/endpoints/check-access.d.ts.map +1 -0
- package/dist/store/endpoints/check-access.js +20 -0
- package/dist/store/endpoints/get-membership.d.ts +19 -0
- package/dist/store/endpoints/get-membership.d.ts.map +1 -0
- package/dist/store/endpoints/get-membership.js +18 -0
- package/dist/store/endpoints/get-plan.d.ts +18 -0
- package/dist/store/endpoints/get-plan.d.ts.map +1 -0
- package/dist/store/endpoints/get-plan.js +17 -0
- package/dist/store/endpoints/list-plans.d.ts +11 -0
- package/dist/store/endpoints/list-plans.d.ts.map +1 -0
- package/dist/store/endpoints/list-plans.js +18 -0
- package/dist/store/endpoints/routes.d.ts +82 -0
- package/dist/store/endpoints/routes.d.ts.map +1 -0
- package/dist/store/endpoints/routes.js +14 -0
- package/dist/store/endpoints/subscribe.d.ts +16 -0
- package/dist/store/endpoints/subscribe.d.ts.map +1 -0
- package/dist/store/endpoints/subscribe.js +30 -0
- package/package.json +93 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare function formatPrice(cents: number): string;
|
|
2
|
+
export declare function formatInterval(interval: string): string;
|
|
3
|
+
export declare function formatIntervalFull(interval: string): string;
|
|
4
|
+
export declare function getBenefitIcon(type: string): string;
|
|
5
|
+
export declare function getBenefitLabel(type: string): string;
|
|
6
|
+
export declare function getStatusColor(status: string): {
|
|
7
|
+
bg: string;
|
|
8
|
+
text: string;
|
|
9
|
+
ring: string;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=_utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_utils.d.ts","sourceRoot":"","sources":["../../../src/store/components/_utils.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWvD;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAW3D;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAenD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAepD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG;IAC/C,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACb,CAkCA"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
export function formatPrice(cents) {
|
|
3
|
+
return new Intl.NumberFormat("en-US", {
|
|
4
|
+
style: "currency",
|
|
5
|
+
currency: "USD",
|
|
6
|
+
}).format(cents / 100);
|
|
7
|
+
}
|
|
8
|
+
export function formatInterval(interval) {
|
|
9
|
+
switch (interval) {
|
|
10
|
+
case "monthly":
|
|
11
|
+
return "/mo";
|
|
12
|
+
case "yearly":
|
|
13
|
+
return "/yr";
|
|
14
|
+
case "lifetime":
|
|
15
|
+
return " one-time";
|
|
16
|
+
default:
|
|
17
|
+
return `/${interval}`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function formatIntervalFull(interval) {
|
|
21
|
+
switch (interval) {
|
|
22
|
+
case "monthly":
|
|
23
|
+
return "per month";
|
|
24
|
+
case "yearly":
|
|
25
|
+
return "per year";
|
|
26
|
+
case "lifetime":
|
|
27
|
+
return "one-time payment";
|
|
28
|
+
default:
|
|
29
|
+
return interval;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function getBenefitIcon(type) {
|
|
33
|
+
switch (type) {
|
|
34
|
+
case "discount_percentage":
|
|
35
|
+
return "\u{1F3F7}\uFE0F";
|
|
36
|
+
case "free_shipping":
|
|
37
|
+
return "\u{1F4E6}";
|
|
38
|
+
case "early_access":
|
|
39
|
+
return "\u26A1";
|
|
40
|
+
case "exclusive_products":
|
|
41
|
+
return "\u{1F512}";
|
|
42
|
+
case "priority_support":
|
|
43
|
+
return "\u{1F6E1}\uFE0F";
|
|
44
|
+
default:
|
|
45
|
+
return "\u2728";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export function getBenefitLabel(type) {
|
|
49
|
+
switch (type) {
|
|
50
|
+
case "discount_percentage":
|
|
51
|
+
return "Member Discount";
|
|
52
|
+
case "free_shipping":
|
|
53
|
+
return "Free Shipping";
|
|
54
|
+
case "early_access":
|
|
55
|
+
return "Early Access";
|
|
56
|
+
case "exclusive_products":
|
|
57
|
+
return "Exclusive Products";
|
|
58
|
+
case "priority_support":
|
|
59
|
+
return "Priority Support";
|
|
60
|
+
default:
|
|
61
|
+
return type;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export function getStatusColor(status) {
|
|
65
|
+
switch (status) {
|
|
66
|
+
case "active":
|
|
67
|
+
return {
|
|
68
|
+
bg: "bg-green-50 dark:bg-green-950/30",
|
|
69
|
+
text: "text-green-700 dark:text-green-400",
|
|
70
|
+
ring: "ring-green-600/20 dark:ring-green-400/30",
|
|
71
|
+
};
|
|
72
|
+
case "trial":
|
|
73
|
+
return {
|
|
74
|
+
bg: "bg-blue-50 dark:bg-blue-950/30",
|
|
75
|
+
text: "text-blue-700 dark:text-blue-400",
|
|
76
|
+
ring: "ring-blue-600/20 dark:ring-blue-400/30",
|
|
77
|
+
};
|
|
78
|
+
case "paused":
|
|
79
|
+
return {
|
|
80
|
+
bg: "bg-amber-50 dark:bg-amber-950/30",
|
|
81
|
+
text: "text-amber-700 dark:text-amber-400",
|
|
82
|
+
ring: "ring-amber-600/20 dark:ring-amber-400/30",
|
|
83
|
+
};
|
|
84
|
+
case "cancelled":
|
|
85
|
+
case "expired":
|
|
86
|
+
return {
|
|
87
|
+
bg: "bg-gray-50 dark:bg-gray-800/50",
|
|
88
|
+
text: "text-gray-600 dark:text-gray-400",
|
|
89
|
+
ring: "ring-gray-500/20 dark:ring-gray-400/30",
|
|
90
|
+
};
|
|
91
|
+
default:
|
|
92
|
+
return {
|
|
93
|
+
bg: "bg-gray-50 dark:bg-gray-800/50",
|
|
94
|
+
text: "text-gray-600 dark:text-gray-400",
|
|
95
|
+
ring: "ring-gray-500/20 dark:ring-gray-400/30",
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { MyMembership } from "./my-membership";
|
|
2
|
+
import { PlanDetail } from "./plan-detail";
|
|
3
|
+
import { PlanListing } from "./plan-listing";
|
|
4
|
+
declare const _default: {
|
|
5
|
+
PlanListing: typeof PlanListing;
|
|
6
|
+
PlanDetail: typeof PlanDetail;
|
|
7
|
+
MyMembership: typeof MyMembership;
|
|
8
|
+
};
|
|
9
|
+
export default _default;
|
|
10
|
+
//# sourceMappingURL=mdx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mdx.d.ts","sourceRoot":"","sources":["../../../src/store/components/mdx.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;;;;;;AAE7C,wBAI0B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"my-membership.d.ts","sourceRoot":"","sources":["../../../src/store/components/my-membership.tsx"],"names":[],"mappings":"AAqCA,wBAAgB,YAAY,gCAgM3B"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { useMembershipsApi } from "./_hooks";
|
|
5
|
+
import { formatIntervalFull, formatPrice, getBenefitIcon, getBenefitLabel, getStatusColor, } from "./_utils";
|
|
6
|
+
import MyMembershipTemplate from "./my-membership.mdx";
|
|
7
|
+
export function MyMembership() {
|
|
8
|
+
const api = useMembershipsApi();
|
|
9
|
+
const [cancelling, setCancelling] = useState(false);
|
|
10
|
+
const [cancelled, setCancelled] = useState(false);
|
|
11
|
+
const { data, isLoading } = api.getMyMembership.useQuery();
|
|
12
|
+
const cancelMutation = api.cancel.useMutation();
|
|
13
|
+
if (isLoading) {
|
|
14
|
+
return (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx("div", { className: "h-7 w-40 animate-pulse rounded bg-muted" }), _jsx("div", { className: "mt-2 h-4 w-64 animate-pulse rounded bg-muted-foreground/10" })] }), _jsxs("div", { className: "animate-pulse rounded-xl border border-border p-6", children: [_jsx("div", { className: "h-5 w-24 rounded bg-muted" }), _jsx("div", { className: "mt-3 h-4 w-48 rounded bg-muted-foreground/10" })] })] }));
|
|
15
|
+
}
|
|
16
|
+
const membership = data?.membership;
|
|
17
|
+
const benefits = data?.benefits ?? [];
|
|
18
|
+
if (!membership) {
|
|
19
|
+
return (_jsxs("div", { className: "space-y-6", children: [_jsx("div", { children: _jsx("h1", { className: "font-bold text-2xl text-foreground tracking-tight", children: "My Membership" }) }), _jsxs("div", { className: "rounded-xl border border-border bg-background p-8 text-center", children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "mx-auto mb-3 text-muted-foreground/50", "aria-hidden": "true", children: _jsx("path", { d: "M6 3h12l4 6-10 13L2 9z" }) }), _jsx("p", { className: "font-medium text-foreground text-sm", children: "You don't have an active membership" }), _jsx("p", { className: "mt-1 text-muted-foreground text-sm", children: "Browse our plans and unlock exclusive benefits." }), _jsx("a", { href: "/memberships", className: "mt-4 inline-flex items-center rounded-md bg-foreground px-4 py-2 font-medium text-background text-sm transition-opacity hover:opacity-90", children: "View plans" })] })] }));
|
|
20
|
+
}
|
|
21
|
+
const statusColor = getStatusColor(membership.status);
|
|
22
|
+
const isActive = membership.status === "active" || membership.status === "trial";
|
|
23
|
+
const handleCancel = async () => {
|
|
24
|
+
setCancelling(true);
|
|
25
|
+
try {
|
|
26
|
+
await cancelMutation.mutateAsync({
|
|
27
|
+
membershipId: membership.id,
|
|
28
|
+
});
|
|
29
|
+
setCancelled(true);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// ignore
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
setCancelling(false);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const statusCard = (_jsxs("div", { className: "rounded-xl border border-border bg-background p-6", children: [_jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { children: [_jsx("h2", { className: "font-semibold text-foreground text-lg", children: membership.plan.name }), _jsxs("p", { className: "mt-0.5 text-muted-foreground text-sm", children: [formatPrice(membership.plan.price), " ", formatIntervalFull(membership.plan.billingInterval)] })] }), _jsx("span", { className: `inline-flex items-center rounded-full px-2.5 py-0.5 font-medium text-xs capitalize ring-1 ring-inset ${statusColor.bg} ${statusColor.text} ${statusColor.ring}`, children: cancelled ? "cancelled" : membership.status })] }), _jsxs("div", { className: "mt-4 grid gap-3 text-sm sm:grid-cols-2", children: [_jsxs("div", { children: [_jsx("span", { className: "text-muted-foreground text-xs", children: "Member since" }), _jsx("p", { className: "text-foreground", children: new Date(membership.startDate).toLocaleDateString() })] }), membership.trialEndDate && membership.status === "trial" && (_jsxs("div", { children: [_jsx("span", { className: "text-muted-foreground text-xs", children: "Trial ends" }), _jsx("p", { className: "text-foreground", children: new Date(membership.trialEndDate).toLocaleDateString() })] })), membership.endDate && (_jsxs("div", { children: [_jsx("span", { className: "text-muted-foreground text-xs", children: membership.status === "cancelled" ? "Ends" : "Renews" }), _jsx("p", { className: "text-foreground", children: new Date(membership.endDate).toLocaleDateString() })] }))] })] }));
|
|
39
|
+
const benefitsCard = benefits.length > 0 ? (_jsxs("div", { className: "rounded-xl border border-border bg-background p-6", children: [_jsx("h2", { className: "mb-3 font-semibold text-foreground", children: "Your Benefits" }), _jsx("div", { className: "space-y-2.5", children: benefits.map((b) => (_jsxs("div", { className: "flex items-start gap-3", children: [_jsx("span", { className: "text-base", "aria-hidden": "true", children: getBenefitIcon(b.type) }), _jsxs("div", { children: [_jsxs("p", { className: "font-medium text-foreground text-sm", children: [getBenefitLabel(b.type), b.type === "discount_percentage" && ` — ${b.value}% off`] }), b.description && (_jsx("p", { className: "text-muted-foreground text-xs", children: b.description }))] })] }, b.id))) })] })) : null;
|
|
40
|
+
const actions = isActive && !cancelled ? (_jsxs("div", { className: "flex gap-3", children: [_jsx("a", { href: "/memberships", className: "rounded-md border border-border px-4 py-2 text-foreground text-sm transition-colors hover:bg-muted", children: "Change plan" }), _jsx("button", { type: "button", onClick: handleCancel, disabled: cancelling, className: "rounded-md border border-red-200 px-4 py-2 text-red-600 text-sm transition-colors hover:bg-red-50 disabled:opacity-50 dark:border-red-900 dark:text-red-400 dark:hover:bg-red-950/30", children: cancelling ? "Cancelling..." : "Cancel membership" })] })) : null;
|
|
41
|
+
return (_jsx(MyMembershipTemplate, { statusCard: statusCard, benefitsCard: benefitsCard, actions: actions }));
|
|
42
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<div className="space-y-6">
|
|
2
|
+
<div>
|
|
3
|
+
<h1 className="font-bold text-2xl text-foreground tracking-tight">
|
|
4
|
+
My Membership
|
|
5
|
+
</h1>
|
|
6
|
+
<p className="mt-1 text-muted-foreground text-sm">
|
|
7
|
+
View and manage your membership plan and benefits.
|
|
8
|
+
</p>
|
|
9
|
+
</div>
|
|
10
|
+
{props.statusCard}
|
|
11
|
+
{props.benefitsCard}
|
|
12
|
+
{props.actions}
|
|
13
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-detail.d.ts","sourceRoot":"","sources":["../../../src/store/components/plan-detail.tsx"],"names":[],"mappings":"AA+BA,wBAAgB,UAAU,CAAC,KAAK,EAAE;IACjC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;CAC5C,+BAgNA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { useMembershipsApi } from "./_hooks";
|
|
5
|
+
import { formatInterval, formatIntervalFull, formatPrice, getBenefitIcon, getBenefitLabel, } from "./_utils";
|
|
6
|
+
import PlanDetailTemplate from "./plan-detail.mdx";
|
|
7
|
+
export function PlanDetail(props) {
|
|
8
|
+
const slug = props.slug ?? props.params?.slug;
|
|
9
|
+
const api = useMembershipsApi();
|
|
10
|
+
const [subscribing, setSubscribing] = useState(false);
|
|
11
|
+
const [subscribeResult, setSubscribeResult] = useState(null);
|
|
12
|
+
const { data, isLoading } = api.getPlan.useQuery({ slug: slug ?? "" }, { enabled: Boolean(slug) });
|
|
13
|
+
const subscribeMutation = api.subscribe.useMutation();
|
|
14
|
+
if (!slug) {
|
|
15
|
+
return (_jsx("div", { className: "py-16 text-center", children: _jsx("p", { className: "text-muted-foreground text-sm", children: "Plan not found" }) }));
|
|
16
|
+
}
|
|
17
|
+
if (isLoading) {
|
|
18
|
+
return (_jsxs("div", { className: "mx-auto max-w-2xl animate-pulse space-y-6", children: [_jsx("div", { className: "h-4 w-32 rounded bg-muted-foreground/10" }), _jsx("div", { className: "h-8 w-48 rounded bg-muted" }), _jsx("div", { className: "h-4 w-72 rounded bg-muted-foreground/10" }), _jsx("div", { className: "h-12 w-32 rounded bg-muted" }), _jsxs("div", { className: "space-y-3 rounded-xl border border-border p-6", children: [_jsx("div", { className: "h-5 w-24 rounded bg-muted" }), _jsx("div", { className: "h-4 w-full rounded bg-muted-foreground/10" }), _jsx("div", { className: "h-4 w-3/4 rounded bg-muted-foreground/10" })] })] }));
|
|
19
|
+
}
|
|
20
|
+
if (!data) {
|
|
21
|
+
return (_jsxs("div", { className: "py-16 text-center", children: [_jsx("p", { className: "font-medium text-foreground text-sm", children: "Plan not found" }), _jsx("a", { href: "/memberships", className: "mt-2 inline-block text-muted-foreground text-sm underline", children: "Browse all plans" })] }));
|
|
22
|
+
}
|
|
23
|
+
const { plan, benefits } = data;
|
|
24
|
+
const handleSubscribe = async () => {
|
|
25
|
+
setSubscribing(true);
|
|
26
|
+
setSubscribeResult(null);
|
|
27
|
+
try {
|
|
28
|
+
await subscribeMutation.mutateAsync({
|
|
29
|
+
planId: plan.id,
|
|
30
|
+
});
|
|
31
|
+
setSubscribeResult("success");
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
setSubscribeResult("error");
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
setSubscribing(false);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const header = (_jsxs("div", { children: [_jsx("h1", { className: "font-bold text-2xl text-foreground tracking-tight", children: plan.name }), plan.description && (_jsx("p", { className: "mt-2 text-muted-foreground", children: plan.description })), _jsxs("div", { className: "mt-4 flex items-baseline gap-1.5", children: [_jsx("span", { className: "font-bold text-4xl text-foreground", children: formatPrice(plan.price) }), _jsx("span", { className: "text-muted-foreground", children: formatIntervalFull(plan.billingInterval) })] }), plan.trialDays > 0 && (_jsxs("p", { className: "mt-1 text-green-600 text-sm dark:text-green-400", children: ["Start with a ", plan.trialDays, "-day free trial"] }))] }));
|
|
41
|
+
const benefitsSection = benefits.length > 0 ? (_jsxs("div", { className: "rounded-xl border border-border bg-background p-6", children: [_jsx("h2", { className: "mb-4 font-semibold text-foreground text-lg", children: "Member Benefits" }), _jsx("div", { className: "space-y-3", children: benefits.map((benefit) => (_jsxs("div", { className: "flex items-start gap-3", children: [_jsx("span", { className: "mt-0.5 text-lg", "aria-hidden": "true", children: getBenefitIcon(benefit.type) }), _jsxs("div", { children: [_jsxs("p", { className: "font-medium text-foreground text-sm", children: [getBenefitLabel(benefit.type), benefit.type === "discount_percentage" &&
|
|
42
|
+
` — ${benefit.value}% off`] }), benefit.description && (_jsx("p", { className: "text-muted-foreground text-xs", children: benefit.description }))] })] }, benefit.id))) })] })) : null;
|
|
43
|
+
const featuresSection = plan.features && plan.features.length > 0 ? (_jsxs("div", { className: "rounded-xl border border-border bg-background p-6", children: [_jsx("h2", { className: "mb-4 font-semibold text-foreground text-lg", children: "What's Included" }), _jsx("ul", { className: "space-y-2.5", children: plan.features.map((feature) => (_jsxs("li", { className: "flex items-start gap-2.5 text-muted-foreground text-sm", children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "mt-0.5 shrink-0 text-green-600 dark:text-green-400", "aria-hidden": "true", children: _jsx("polyline", { points: "20 6 9 17 4 12" }) }), feature] }, feature))) })] })) : null;
|
|
44
|
+
const actionSection = (_jsx("div", { className: "space-y-3", children: subscribeResult === "success" ? (_jsxs("div", { className: "rounded-lg border border-green-200 bg-green-50 p-4 text-center dark:border-green-900 dark:bg-green-950/30", children: [_jsx("p", { className: "font-medium text-green-800 text-sm dark:text-green-300", children: "Welcome! Your membership is now active." }), _jsx("a", { href: "/account", className: "mt-1 inline-block text-green-600 text-xs underline dark:text-green-400", children: "Go to your account" })] })) : (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: handleSubscribe, disabled: subscribing, className: "w-full rounded-lg bg-foreground px-6 py-3 font-medium text-background text-sm transition-opacity hover:opacity-90 disabled:opacity-50", children: subscribing
|
|
45
|
+
? "Subscribing..."
|
|
46
|
+
: plan.trialDays > 0
|
|
47
|
+
? `Start ${plan.trialDays}-day free trial`
|
|
48
|
+
: `Subscribe — ${formatPrice(plan.price)}${formatInterval(plan.billingInterval)}` }), subscribeResult === "error" && (_jsx("p", { className: "text-center text-red-500 text-sm", children: "Could not subscribe. Please sign in and try again." }))] })) }));
|
|
49
|
+
return (_jsx(PlanDetailTemplate, { planName: plan.name, header: header, benefitsSection: benefitsSection, featuresSection: featuresSection, actionSection: actionSection }));
|
|
50
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
|
|
3
|
+
<div className="mx-auto max-w-2xl space-y-8">
|
|
4
|
+
<div>
|
|
5
|
+
<nav className="mb-4 flex items-center gap-2 text-muted-foreground text-sm">
|
|
6
|
+
<Link href="/memberships" className="transition-colors hover:text-foreground">Memberships</Link>
|
|
7
|
+
<span>/</span>
|
|
8
|
+
<span className="text-foreground">{props.planName}</span>
|
|
9
|
+
</nav>
|
|
10
|
+
{props.header}
|
|
11
|
+
</div>
|
|
12
|
+
{props.benefitsSection}
|
|
13
|
+
{props.featuresSection}
|
|
14
|
+
{props.actionSection}
|
|
15
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-listing.d.ts","sourceRoot":"","sources":["../../../src/store/components/plan-listing.tsx"],"names":[],"mappings":"AAqBA,wBAAgB,WAAW,gCAmJ1B"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import { useMembershipsApi } from "./_hooks";
|
|
5
|
+
import { formatInterval, formatPrice } from "./_utils";
|
|
6
|
+
import PlanListingTemplate from "./plan-listing.mdx";
|
|
7
|
+
const PLAN_SKELETON_IDS = ["a", "b", "c"];
|
|
8
|
+
export function PlanListing() {
|
|
9
|
+
const api = useMembershipsApi();
|
|
10
|
+
const { data, isLoading } = api.listPlans.useQuery();
|
|
11
|
+
const plans = data?.plans ?? [];
|
|
12
|
+
if (isLoading) {
|
|
13
|
+
return (_jsxs("div", { className: "space-y-8", children: [_jsxs("div", { className: "text-center", children: [_jsx("div", { className: "mx-auto h-8 w-48 animate-pulse rounded bg-muted" }), _jsx("div", { className: "mx-auto mt-3 h-4 w-72 animate-pulse rounded bg-muted-foreground/10" })] }), _jsx("div", { className: "mx-auto grid max-w-5xl gap-6 sm:grid-cols-2 lg:grid-cols-3", children: PLAN_SKELETON_IDS.map((id) => (_jsxs("div", { className: "animate-pulse rounded-xl border border-border p-6", children: [_jsx("div", { className: "mb-4 h-5 w-24 rounded bg-muted" }), _jsx("div", { className: "mb-2 h-8 w-20 rounded bg-muted" }), _jsx("div", { className: "mb-6 h-3 w-16 rounded bg-muted-foreground/10" }), _jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "h-3 w-full rounded bg-muted-foreground/10" }), _jsx("div", { className: "h-3 w-3/4 rounded bg-muted-foreground/10" }), _jsx("div", { className: "h-3 w-5/6 rounded bg-muted-foreground/10" })] }), _jsx("div", { className: "mt-6 h-10 w-full rounded bg-muted" })] }, `plan-skel-${id}`))) })] }));
|
|
14
|
+
}
|
|
15
|
+
if (plans.length === 0) {
|
|
16
|
+
return (_jsxs("div", { className: "flex flex-col items-center justify-center py-20 text-center", children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "mb-3 text-muted-foreground/50", "aria-hidden": "true", children: _jsx("path", { d: "M6 3h12l4 6-10 13L2 9z" }) }), _jsx("p", { className: "font-medium text-foreground text-sm", children: "No membership plans available" }), _jsx("p", { className: "mt-1 text-muted-foreground text-sm", children: "Check back soon for exclusive membership offers" })] }));
|
|
17
|
+
}
|
|
18
|
+
const sorted = [...plans].sort((a, b) => a.sortOrder - b.sortOrder);
|
|
19
|
+
const planCards = sorted.map((plan) => (_jsxs(Link, { href: `/memberships/${plan.slug}`, className: "group flex flex-col rounded-xl border border-border bg-background p-6 transition-shadow hover:shadow-md", children: [_jsx("h3", { className: "font-semibold text-foreground text-lg transition-colors group-hover:text-foreground/80", children: plan.name }), plan.description && (_jsx("p", { className: "mt-1 text-muted-foreground text-sm", children: plan.description })), _jsxs("div", { className: "mt-4 flex items-baseline gap-1", children: [_jsx("span", { className: "font-bold text-3xl text-foreground", children: formatPrice(plan.price) }), _jsx("span", { className: "text-muted-foreground text-sm", children: formatInterval(plan.billingInterval) })] }), plan.trialDays > 0 && (_jsxs("p", { className: "mt-1 text-muted-foreground text-xs", children: [plan.trialDays, "-day free trial"] })), plan.features && plan.features.length > 0 && (_jsx("ul", { className: "mt-4 flex-1 space-y-2", children: plan.features.map((feature) => (_jsxs("li", { className: "flex items-start gap-2 text-muted-foreground text-sm", children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "mt-0.5 shrink-0 text-green-600 dark:text-green-400", "aria-hidden": "true", children: _jsx("polyline", { points: "20 6 9 17 4 12" }) }), feature] }, feature))) })), _jsxs("div", { className: "mt-6 flex items-center justify-center rounded-md border border-border px-4 py-2 font-medium text-foreground text-sm transition-colors group-hover:bg-muted", children: ["View plan", _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "ml-1.5", "aria-hidden": "true", children: _jsx("path", { d: "m9 18 6-6-6-6" }) })] })] }, plan.id)));
|
|
20
|
+
return _jsx(PlanListingTemplate, { planCards: planCards });
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<div className="space-y-8">
|
|
2
|
+
<div className="text-center">
|
|
3
|
+
<h1 className="font-bold text-3xl text-foreground tracking-tight">
|
|
4
|
+
Membership Plans
|
|
5
|
+
</h1>
|
|
6
|
+
<p className="mx-auto mt-2 max-w-xl text-muted-foreground">
|
|
7
|
+
Unlock exclusive benefits, member-only pricing, and early access to new products.
|
|
8
|
+
</p>
|
|
9
|
+
</div>
|
|
10
|
+
<div className="mx-auto grid max-w-5xl gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
|
11
|
+
{props.planCards}
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const cancel: import("better-call").StrictEndpoint<"/memberships/cancel", {
|
|
3
|
+
method: "POST";
|
|
4
|
+
body: z.ZodObject<{
|
|
5
|
+
membershipId: z.ZodString;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
}, {
|
|
8
|
+
error: string;
|
|
9
|
+
status: number;
|
|
10
|
+
membership?: never;
|
|
11
|
+
} | {
|
|
12
|
+
membership: import("../..").Membership;
|
|
13
|
+
error?: never;
|
|
14
|
+
status?: never;
|
|
15
|
+
}>;
|
|
16
|
+
//# sourceMappingURL=cancel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cancel.d.ts","sourceRoot":"","sources":["../../../src/store/endpoints/cancel.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,MAAM;;;;;;;;;;;;;EA8BlB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createStoreEndpoint } from "@86d-store/core/api";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export const cancel = createStoreEndpoint("/memberships/cancel", {
|
|
4
|
+
method: "POST",
|
|
5
|
+
body: z.object({
|
|
6
|
+
membershipId: z.string().min(1).max(200),
|
|
7
|
+
}),
|
|
8
|
+
}, async (ctx) => {
|
|
9
|
+
const session = ctx.context.session;
|
|
10
|
+
if (!session) {
|
|
11
|
+
return { error: "Authentication required", status: 401 };
|
|
12
|
+
}
|
|
13
|
+
const controller = ctx.context.controllers
|
|
14
|
+
.memberships;
|
|
15
|
+
// Verify ownership before mutating
|
|
16
|
+
const existing = await controller.getMembership(ctx.body.membershipId);
|
|
17
|
+
if (!existing || existing.customerId !== session.user.id) {
|
|
18
|
+
return { error: "Membership not found", status: 404 };
|
|
19
|
+
}
|
|
20
|
+
const membership = await controller.cancelMembership(ctx.body.membershipId);
|
|
21
|
+
if (!membership) {
|
|
22
|
+
return { error: "Membership not found", status: 404 };
|
|
23
|
+
}
|
|
24
|
+
return { membership };
|
|
25
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const checkAccess: import("better-call").StrictEndpoint<"/memberships/check-access", {
|
|
3
|
+
method: "GET";
|
|
4
|
+
query: z.ZodObject<{
|
|
5
|
+
productId: z.ZodString;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
}, {
|
|
8
|
+
hasAccess: boolean;
|
|
9
|
+
}>;
|
|
10
|
+
//# sourceMappingURL=check-access.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-access.d.ts","sourceRoot":"","sources":["../../../src/store/endpoints/check-access.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,WAAW;;;;;;;EAwBvB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createStoreEndpoint } from "@86d-store/core/api";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export const checkAccess = createStoreEndpoint("/memberships/check-access", {
|
|
4
|
+
method: "GET",
|
|
5
|
+
query: z.object({
|
|
6
|
+
productId: z.string().min(1).max(200),
|
|
7
|
+
}),
|
|
8
|
+
}, async (ctx) => {
|
|
9
|
+
const session = ctx.context.session;
|
|
10
|
+
if (!session) {
|
|
11
|
+
return { hasAccess: false };
|
|
12
|
+
}
|
|
13
|
+
const controller = ctx.context.controllers
|
|
14
|
+
.memberships;
|
|
15
|
+
const hasAccess = await controller.canAccessProduct({
|
|
16
|
+
customerId: session.user.id,
|
|
17
|
+
productId: ctx.query.productId,
|
|
18
|
+
});
|
|
19
|
+
return { hasAccess };
|
|
20
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const getMembership: import("better-call").StrictEndpoint<"/memberships/my-membership", {
|
|
2
|
+
method: "GET";
|
|
3
|
+
}, {
|
|
4
|
+
error: string;
|
|
5
|
+
status: number;
|
|
6
|
+
membership?: never;
|
|
7
|
+
benefits?: never;
|
|
8
|
+
} | {
|
|
9
|
+
membership: null;
|
|
10
|
+
benefits: never[];
|
|
11
|
+
error?: never;
|
|
12
|
+
status?: never;
|
|
13
|
+
} | {
|
|
14
|
+
membership: import("../..").MembershipWithPlan;
|
|
15
|
+
benefits: import("../..").MembershipBenefit[];
|
|
16
|
+
error?: never;
|
|
17
|
+
status?: never;
|
|
18
|
+
}>;
|
|
19
|
+
//# sourceMappingURL=get-membership.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-membership.d.ts","sourceRoot":"","sources":["../../../src/store/endpoints/get-membership.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;EAwBzB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createStoreEndpoint } from "@86d-store/core/api";
|
|
2
|
+
export const getMembership = createStoreEndpoint("/memberships/my-membership", {
|
|
3
|
+
method: "GET",
|
|
4
|
+
}, async (ctx) => {
|
|
5
|
+
const session = ctx.context.session;
|
|
6
|
+
if (!session) {
|
|
7
|
+
return { error: "Authentication required", status: 401 };
|
|
8
|
+
}
|
|
9
|
+
const controller = ctx.context.controllers
|
|
10
|
+
.memberships;
|
|
11
|
+
const customerId = session.user.id;
|
|
12
|
+
const membership = await controller.getCustomerMembership(customerId);
|
|
13
|
+
if (!membership) {
|
|
14
|
+
return { membership: null, benefits: [] };
|
|
15
|
+
}
|
|
16
|
+
const benefits = await controller.getCustomerBenefits(customerId);
|
|
17
|
+
return { membership, benefits };
|
|
18
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const getPlan: import("better-call").StrictEndpoint<"/memberships/plans/:slug", {
|
|
3
|
+
method: "GET";
|
|
4
|
+
params: z.ZodObject<{
|
|
5
|
+
slug: z.ZodString;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
}, {
|
|
8
|
+
error: string;
|
|
9
|
+
status: number;
|
|
10
|
+
plan?: never;
|
|
11
|
+
benefits?: never;
|
|
12
|
+
} | {
|
|
13
|
+
plan: import("../..").MembershipPlan;
|
|
14
|
+
benefits: import("../..").MembershipBenefit[];
|
|
15
|
+
error?: never;
|
|
16
|
+
status?: never;
|
|
17
|
+
}>;
|
|
18
|
+
//# sourceMappingURL=get-plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-plan.d.ts","sourceRoot":"","sources":["../../../src/store/endpoints/get-plan.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;EAqBnB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createStoreEndpoint } from "@86d-store/core/api";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export const getPlan = createStoreEndpoint("/memberships/plans/:slug", {
|
|
4
|
+
method: "GET",
|
|
5
|
+
params: z.object({
|
|
6
|
+
slug: z.string().min(1).max(200),
|
|
7
|
+
}),
|
|
8
|
+
}, async (ctx) => {
|
|
9
|
+
const controller = ctx.context.controllers
|
|
10
|
+
.memberships;
|
|
11
|
+
const plan = await controller.getPlanBySlug(ctx.params.slug);
|
|
12
|
+
if (!plan?.isActive) {
|
|
13
|
+
return { error: "Plan not found", status: 404 };
|
|
14
|
+
}
|
|
15
|
+
const benefits = await controller.listBenefits(plan.id);
|
|
16
|
+
return { plan, benefits: benefits.filter((b) => b.isActive) };
|
|
17
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const listPlans: import("better-call").StrictEndpoint<"/memberships/plans", {
|
|
3
|
+
method: "GET";
|
|
4
|
+
query: z.ZodObject<{
|
|
5
|
+
take: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
6
|
+
skip: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
}, {
|
|
9
|
+
plans: import("../..").MembershipPlan[];
|
|
10
|
+
}>;
|
|
11
|
+
//# sourceMappingURL=list-plans.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-plans.d.ts","sourceRoot":"","sources":["../../../src/store/endpoints/list-plans.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,SAAS;;;;;;;;EAqBrB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createStoreEndpoint } from "@86d-store/core/api";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export const listPlans = createStoreEndpoint("/memberships/plans", {
|
|
4
|
+
method: "GET",
|
|
5
|
+
query: z.object({
|
|
6
|
+
take: z.coerce.number().int().min(1).max(100).optional(),
|
|
7
|
+
skip: z.coerce.number().int().min(0).optional(),
|
|
8
|
+
}),
|
|
9
|
+
}, async (ctx) => {
|
|
10
|
+
const controller = ctx.context.controllers
|
|
11
|
+
.memberships;
|
|
12
|
+
const plans = await controller.listPlans({
|
|
13
|
+
isActive: true,
|
|
14
|
+
take: ctx.query.take ?? 50,
|
|
15
|
+
skip: ctx.query.skip ?? 0,
|
|
16
|
+
});
|
|
17
|
+
return { plans };
|
|
18
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export declare const storeEndpoints: {
|
|
2
|
+
"/memberships/plans": import("better-call").StrictEndpoint<"/memberships/plans", {
|
|
3
|
+
method: "GET";
|
|
4
|
+
query: import("zod").ZodObject<{
|
|
5
|
+
take: import("zod").ZodOptional<import("zod").ZodCoercedNumber<unknown>>;
|
|
6
|
+
skip: import("zod").ZodOptional<import("zod").ZodCoercedNumber<unknown>>;
|
|
7
|
+
}, import("zod/v4/core").$strip>;
|
|
8
|
+
}, {
|
|
9
|
+
plans: import("../..").MembershipPlan[];
|
|
10
|
+
}>;
|
|
11
|
+
"/memberships/plans/:slug": import("better-call").StrictEndpoint<"/memberships/plans/:slug", {
|
|
12
|
+
method: "GET";
|
|
13
|
+
params: import("zod").ZodObject<{
|
|
14
|
+
slug: import("zod").ZodString;
|
|
15
|
+
}, import("zod/v4/core").$strip>;
|
|
16
|
+
}, {
|
|
17
|
+
error: string;
|
|
18
|
+
status: number;
|
|
19
|
+
plan?: never;
|
|
20
|
+
benefits?: never;
|
|
21
|
+
} | {
|
|
22
|
+
plan: import("../..").MembershipPlan;
|
|
23
|
+
benefits: import("../..").MembershipBenefit[];
|
|
24
|
+
error?: never;
|
|
25
|
+
status?: never;
|
|
26
|
+
}>;
|
|
27
|
+
"/memberships/my-membership": import("better-call").StrictEndpoint<"/memberships/my-membership", {
|
|
28
|
+
method: "GET";
|
|
29
|
+
}, {
|
|
30
|
+
error: string;
|
|
31
|
+
status: number;
|
|
32
|
+
membership?: never;
|
|
33
|
+
benefits?: never;
|
|
34
|
+
} | {
|
|
35
|
+
membership: null;
|
|
36
|
+
benefits: never[];
|
|
37
|
+
error?: never;
|
|
38
|
+
status?: never;
|
|
39
|
+
} | {
|
|
40
|
+
membership: import("../..").MembershipWithPlan;
|
|
41
|
+
benefits: import("../..").MembershipBenefit[];
|
|
42
|
+
error?: never;
|
|
43
|
+
status?: never;
|
|
44
|
+
}>;
|
|
45
|
+
"/memberships/subscribe": import("better-call").StrictEndpoint<"/memberships/subscribe", {
|
|
46
|
+
method: "POST";
|
|
47
|
+
body: import("zod").ZodObject<{
|
|
48
|
+
planId: import("zod").ZodString;
|
|
49
|
+
}, import("zod/v4/core").$strip>;
|
|
50
|
+
}, {
|
|
51
|
+
error: string;
|
|
52
|
+
status: number;
|
|
53
|
+
membership?: never;
|
|
54
|
+
} | {
|
|
55
|
+
membership: import("../..").Membership;
|
|
56
|
+
error?: never;
|
|
57
|
+
status?: never;
|
|
58
|
+
}>;
|
|
59
|
+
"/memberships/cancel": import("better-call").StrictEndpoint<"/memberships/cancel", {
|
|
60
|
+
method: "POST";
|
|
61
|
+
body: import("zod").ZodObject<{
|
|
62
|
+
membershipId: import("zod").ZodString;
|
|
63
|
+
}, import("zod/v4/core").$strip>;
|
|
64
|
+
}, {
|
|
65
|
+
error: string;
|
|
66
|
+
status: number;
|
|
67
|
+
membership?: never;
|
|
68
|
+
} | {
|
|
69
|
+
membership: import("../..").Membership;
|
|
70
|
+
error?: never;
|
|
71
|
+
status?: never;
|
|
72
|
+
}>;
|
|
73
|
+
"/memberships/check-access": import("better-call").StrictEndpoint<"/memberships/check-access", {
|
|
74
|
+
method: "GET";
|
|
75
|
+
query: import("zod").ZodObject<{
|
|
76
|
+
productId: import("zod").ZodString;
|
|
77
|
+
}, import("zod/v4/core").$strip>;
|
|
78
|
+
}, {
|
|
79
|
+
hasAccess: boolean;
|
|
80
|
+
}>;
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=routes.d.ts.map
|