|
1 | | -import { getOfflineLicenseKey, SOURCEBOT_UNLIMITED_SEATS } from "@sourcebot/shared"; |
2 | | -import { getEntitlements, getPlan } from "@/lib/entitlements"; |
3 | | -import { Button } from "@/components/ui/button"; |
4 | | -import { Info, Mail } from "lucide-react"; |
5 | | -import { getOrgMembers } from "@/actions"; |
6 | | -import { isServiceError } from "@/lib/utils"; |
7 | | -import { ServiceErrorException } from "@/lib/serviceError"; |
8 | 1 | import { authenticatedPage } from "@/middleware/authenticatedPage"; |
9 | 2 | import { OrgRole } from "@sourcebot/db"; |
| 3 | +import { ActivationCodeCard } from "./activationCodeCard"; |
| 4 | +import { PurchaseButton } from "./purchaseButton"; |
10 | 5 |
|
11 | | -export default authenticatedPage(async () => { |
12 | | - const licenseKey = getOfflineLicenseKey(); |
13 | | - const entitlements = await getEntitlements(); |
14 | | - const plan = await getPlan(); |
15 | | - |
16 | | - if (!licenseKey) { |
17 | | - return ( |
18 | | - <div className="flex flex-col gap-6"> |
19 | | - <div> |
20 | | - <h3 className="text-lg font-medium">License</h3> |
21 | | - <p className="text-sm text-muted-foreground">View your license details.</p> |
22 | | - </div> |
23 | | - |
24 | | - <div className="flex flex-col items-center justify-center p-8 border rounded-md bg-card"> |
25 | | - <Info className="h-12 w-12 text-muted-foreground mb-4" /> |
26 | | - <h3 className="text-lg font-medium mb-2">No License Found</h3> |
27 | | - <p className="text-sm text-muted-foreground text-center max-w-md mb-6"> |
28 | | - Check out the <a href="https://docs.sourcebot.dev/docs/license-key" target="_blank" rel="noopener noreferrer" className="text-primary">docs</a> for more information. |
29 | | - </p> |
30 | | - <div className="mb-8 max-w-md rounded-lg bg-slate-50 p-4 dark:bg-slate-800"> |
31 | | - <p className="text-base text-center"> |
32 | | - Want to try out Sourcebot's enterprise features? Reach out to us and we'll get back to you within |
33 | | - a couple hours with a trial license. |
34 | | - </p> |
35 | | - </div> |
36 | | - <Button asChild> |
37 | | - <a href={`https://sourcebot.dev/contact`} target="_blank" rel="noopener noreferrer"> |
38 | | - <Mail className="h-4 w-4 mr-2" /> |
39 | | - Request a trial license |
40 | | - </a> |
41 | | - </Button> |
42 | | - </div> |
43 | | - </div> |
44 | | - ) |
45 | | - } |
46 | | - |
47 | | - const members = await getOrgMembers(); |
48 | | - if (isServiceError(members)) { |
49 | | - throw new ServiceErrorException(members); |
50 | | - } |
51 | | - |
52 | | - const numMembers = members.length; |
53 | | - const expiryDate = new Date(licenseKey.expiryDate); |
54 | | - const isExpired = expiryDate < new Date(); |
55 | | - const seats = licenseKey.seats; |
56 | | - const isUnlimited = seats === SOURCEBOT_UNLIMITED_SEATS; |
| 6 | +export default authenticatedPage(async ({ prisma, org }) => { |
| 7 | + const license = await prisma.license.findUnique({ |
| 8 | + where: { orgId: org.id }, |
| 9 | + }); |
57 | 10 |
|
58 | 11 | return ( |
59 | 12 | <div className="flex flex-col gap-6"> |
60 | | - <div className="flex items-start justify-between"> |
61 | | - <div> |
62 | | - <h3 className="text-lg font-medium">License</h3> |
63 | | - <p className="text-sm text-muted-foreground">View your license details.</p> |
64 | | - </div> |
65 | | - |
66 | | - <Button asChild> |
67 | | - <a href={`mailto:team@sourcebot.dev?subject=License Support - ${licenseKey.id}&body=License ID: ${licenseKey.id}`}> |
68 | | - <Mail className="h-4 w-4 mr-2" /> |
69 | | - Contact Support |
70 | | - </a> |
71 | | - </Button> |
72 | | - </div> |
73 | | - |
74 | | - <div className="grid gap-6"> |
75 | | - <div className="border rounded-md p-6 bg-card"> |
76 | | - <h4 className="text-base font-medium mb-4">License Details</h4> |
77 | | - |
78 | | - <div className="grid gap-4"> |
79 | | - <div className="grid grid-cols-2 gap-4"> |
80 | | - <div className="text-sm text-muted-foreground">License ID</div> |
81 | | - <div className="text-sm font-mono">{licenseKey.id}</div> |
82 | | - </div> |
83 | | - |
84 | | - <div className="grid grid-cols-2 gap-4"> |
85 | | - <div className="text-sm text-muted-foreground">Plan</div> |
86 | | - <div className="text-sm font-mono">{plan}</div> |
87 | | - </div> |
88 | | - |
89 | | - <div className="grid grid-cols-2 gap-4"> |
90 | | - <div className="text-sm text-muted-foreground">Entitlements</div> |
91 | | - <div className="text-sm font-mono">{entitlements?.join(", ") || "None"}</div> |
92 | | - </div> |
93 | | - |
94 | | - <div className="grid grid-cols-2 gap-4"> |
95 | | - <div className="text-sm text-muted-foreground">Seats</div> |
96 | | - <div className="text-sm font-mono"> |
97 | | - {isUnlimited ? 'Unlimited' : `${numMembers} / ${seats}`} |
98 | | - </div> |
99 | | - </div> |
100 | | - |
101 | | - <div className="grid grid-cols-2 gap-4"> |
102 | | - <div className="text-sm text-muted-foreground">Expiry Date</div> |
103 | | - <div className={`text-sm font-mono ${isExpired ? 'text-destructive' : ''}`}> |
104 | | - {expiryDate.toLocaleString("en-US", { |
105 | | - hour: "2-digit", |
106 | | - minute: "2-digit", |
107 | | - month: "long", |
108 | | - day: "numeric", |
109 | | - year: "numeric", |
110 | | - timeZoneName: "short" |
111 | | - })} {isExpired && '(Expired)'} |
112 | | - </div> |
113 | | - </div> |
114 | | - </div> |
115 | | - </div> |
| 13 | + <div> |
| 14 | + <h3 className="text-lg font-medium">License</h3> |
| 15 | + <p className="text-sm text-muted-foreground">Manage your license.</p> |
116 | 16 | </div> |
| 17 | + <ActivationCodeCard isActivated={!!license} /> |
| 18 | + <PurchaseButton /> |
117 | 19 | </div> |
118 | | - ) |
119 | | -}, { minRole: OrgRole.OWNER, redirectTo: '/settings' }); |
| 20 | + ); |
| 21 | +}, { |
| 22 | + minRole: OrgRole.OWNER, |
| 23 | + redirectTo: '/settings' |
| 24 | +}); |
0 commit comments