Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/billing/plan-badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function PlanBadge({
return (
<span
className={cn(
"ml-1 inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-xs uppercase text-gray-700 ring-1 ring-gray-400 hover:bg-gray-200 dark:text-foreground dark:ring-gray-500 hover:dark:bg-gray-700",
"ml-1 inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-xs font-normal uppercase tracking-normal text-gray-700 ring-1 ring-gray-400 hover:bg-gray-200 dark:text-foreground dark:ring-gray-500 hover:dark:bg-gray-700",
className,
)}
>
Expand Down
17 changes: 12 additions & 5 deletions components/billing/upgrade-plan-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import { getPriceIdFromPlan } from "@/ee/stripe/functions/get-price-id-from-plan
import { PLANS } from "@/ee/stripe/utils";
import { CheckIcon, Users2Icon } from "lucide-react";

import { useAnalytics } from "@/lib/analytics";
import { usePlan } from "@/lib/swr/use-billing";
import { capitalize, cn } from "@/lib/utils";

import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
import { Switch } from "@/components/ui/switch";
Expand All @@ -21,10 +25,6 @@ import {
TooltipTrigger,
} from "@/components/ui/tooltip";

import { useAnalytics } from "@/lib/analytics";
import { usePlan } from "@/lib/swr/use-billing";
import { capitalize, cn } from "@/lib/utils";

// Feature rendering component
const FeatureItem = ({ feature }: { feature: Feature }) => {
const baseClasses = `flex items-center ${feature.isHighlighted ? "bg-orange-50 -mx-6 px-6 py-2 -my-1 font-bold rounded-md dark:bg-orange-900/20" : ""}`;
Expand Down Expand Up @@ -103,12 +103,14 @@ export function UpgradePlanModal({
trigger,
open,
setOpen,
highlightItem,
children,
}: {
clickedPlan: PlanEnum;
trigger?: string;
open?: boolean;
setOpen?: React.Dispatch<React.SetStateAction<boolean>>;
highlightItem?: string[];
children?: React.ReactNode;
}) {
const router = useRouter();
Expand Down Expand Up @@ -261,7 +263,12 @@ export function UpgradePlanModal({
<ul className="mb-6 mt-2 space-y-2 text-sm leading-6 text-gray-600 dark:text-muted-foreground">
{planFeatures.features.map((feature, i) => (
<li key={i}>
<FeatureItem feature={feature} />
<FeatureItem
feature={{
...feature,
isHighlighted: highlightItem?.includes(feature.id),
}}
/>
</li>
))}
</ul>
Expand Down
2 changes: 1 addition & 1 deletion components/datarooms/dataroom-navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const DataroomNavigation = ({ dataroomId }: { dataroomId?: string }) => {
label: "Q&A Conversations",
href: `/datarooms/${dataroomId}/conversations`,
segment: "conversations",
disabled: !limits?.conversationsInDataroom,
limited: !limits?.conversationsInDataroom,
},
{
label: "Branding",
Expand Down
78 changes: 51 additions & 27 deletions components/navigation-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@ import { useRouter } from "next/router";

import * as React from "react";

import { Separator } from "@/components/ui/separator";
import { PlanEnum } from "@/ee/stripe/constants";
import { CrownIcon } from "lucide-react";

import { cn } from "@/lib/utils";

import { Separator } from "@/components/ui/separator";

import { UpgradePlanModal } from "./billing/upgrade-plan-modal";

type Props = {
navigation: {
label: string;
href: string;
segment: string | null;
tag?: string;
disabled?: boolean;
limited?: boolean;
}[];
className?: string;
};
Expand All @@ -30,16 +36,19 @@ export const NavMenu: React.FC<React.PropsWithChildren<Props>> = ({
>
<div className="flex w-full items-center overflow-x-auto px-4 pl-1">
<ul className="flex flex-row gap-4">
{navigation.map(({ label, href, segment, tag, disabled }) => (
<NavItem
key={label}
label={label}
href={href}
segment={segment}
tag={tag}
disabled={disabled}
/>
))}
{navigation.map(
({ label, href, segment, tag, disabled, limited }) => (
<NavItem
key={label}
label={label}
href={href}
segment={segment}
tag={tag}
disabled={disabled}
limited={limited}
/>
),
)}
</ul>
</div>
<Separator />
Expand All @@ -53,6 +62,7 @@ const NavItem: React.FC<Props["navigation"][0]> = ({
segment,
tag,
disabled,
limited,
}) => {
const router = useRouter();
// active is true if the segment included in the pathname, but not if it's the root pathname. unless the segment is the root pathname.
Expand All @@ -75,31 +85,45 @@ const NavItem: React.FC<Props["navigation"][0]> = ({

return (
<li
key={label}
className={cn(
"flex shrink-0 list-none border-b-2 border-transparent p-2",
{
"border-primary": active,
// "animate-pulse": isPending,
hidden: disabled,
},
)}
>
<Link
href={href}
className={cn(
"text-content-subtle hover:bg-background-subtle -mx-3 flex items-center gap-1 rounded-lg px-3 py-2 text-sm font-medium hover:bg-muted hover:text-primary",
{
"text-primary": active,
},
)}
>
{label}
{tag ? (
<div className="text-content-subtle rounded border bg-background px-1 py-0.5 font-mono text-xs">
{tag}
{limited ? (
<UpgradePlanModal
key={label}
clickedPlan={PlanEnum.DataRoomsPlus}
trigger={label}
highlightItem={["qa"]}
>
<div className="text-content-subtle hover:bg-background-subtle -mx-3 flex items-center gap-1 rounded-lg px-3 py-2 text-sm font-medium hover:bg-muted hover:text-primary">
{label}
<CrownIcon className="h-4 w-4 text-muted-foreground" />
</div>
) : null}
</Link>
</UpgradePlanModal>
) : (
<Link
href={href}
className={cn(
"text-content-subtle hover:bg-background-subtle -mx-3 flex items-center gap-1 rounded-lg px-3 py-2 text-sm font-medium hover:bg-muted hover:text-primary",
{
"text-primary": active,
},
)}
>
{label}
{tag ? (
<div className="text-content-subtle rounded border bg-background px-1 py-0.5 font-mono text-xs">
{tag}
</div>
) : null}
</Link>
)}
</li>
);
};
18 changes: 8 additions & 10 deletions components/settings/settings-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export function SettingsHeader() {
const { data: features } = useSWR<{
tokens: boolean;
incomingWebhooks: boolean;
webhooks: boolean;
}>(
teamInfo?.currentTeam?.id
? `/api/feature-flags?teamId=${teamInfo.currentTeam.id}`
Expand Down Expand Up @@ -59,28 +58,27 @@ export function SettingsHeader() {
segment: "tags",
},
{
label: "Billing",
href: `/settings/billing`,
segment: "billing",
label: "Webhooks",
href: `/settings/webhooks`,
segment: "webhooks",
},
{
label: "Tokens",
href: `/settings/tokens`,
segment: "tokens",
disabled: !features?.tokens,
},
{
label: "Webhooks",
href: `/settings/webhooks`,
segment: "webhooks",
disabled: !features?.webhooks,
},
{
label: "Incoming Webhooks",
href: `/settings/incoming-webhooks`,
segment: "incoming-webhooks",
disabled: !features?.incomingWebhooks,
},
{
label: "Billing",
href: `/settings/billing`,
segment: "billing",
},
]}
/>
</header>
Expand Down
5 changes: 5 additions & 0 deletions components/sidebar/app-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
url: "/settings/domains",
current: router.pathname.includes("settings/domains"),
},
{
title: "Webhooks",
url: "/settings/webhooks",
current: router.pathname.includes("settings/webhooks"),
},
{
title: "Billing",
url: "/settings/billing",
Expand Down
4 changes: 2 additions & 2 deletions components/sidebar/nav-main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import Link from "next/link";
import { PlanEnum } from "@/ee/stripe/constants";
import { ChevronRight, CrownIcon, type LucideIcon } from "lucide-react";

import { cn } from "@/lib/utils";

import {
Collapsible,
CollapsibleContent,
Expand All @@ -22,8 +24,6 @@ import {
SidebarMenuSubItem,
} from "@/components/ui/sidebar";

import { cn } from "@/lib/utils";

import { UpgradePlanModal } from "../billing/upgrade-plan-modal";

export interface NavItem {
Expand Down
1 change: 1 addition & 0 deletions ee/limits/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,6 @@ export const DATAROOMS_PLUS_PLAN_LIMITS = {
datarooms: 1000,
customDomainOnPro: true,
customDomainInDataroom: true,
conversationsInDataroom: true,
advancedLinkControlsOnPro: false,
};
55 changes: 33 additions & 22 deletions pages/settings/webhooks/[id]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { useEffect, useState } from "react";

import { useTeam } from "@/context/team-context";
import { Webhook } from "@prisma/client";
import { format } from "date-fns";
import { ArrowLeft, Check, Copy, WebhookIcon } from "lucide-react";
import { toast } from "sonner";
import useSWR from "swr";

import { usePlan } from "@/lib/swr/use-billing";
import { cn, fetcher } from "@/lib/utils";

import AppLayout from "@/components/layouts/app";
Expand All @@ -32,23 +32,14 @@ export default function WebhookDetail() {
const router = useRouter();
const { id } = router.query;
const teamInfo = useTeam();
const { isFree, isPro } = usePlan();
const teamId = teamInfo?.currentTeam?.id;
const [isEditing, setIsEditing] = useState(false);
const [isCopied, setIsCopied] = useState(false);

// Feature flag check
const { data: features } = useSWR<{ webhooks: boolean }>(
teamId ? `/api/feature-flags?teamId=${teamId}` : null,
fetcher,
);

// Redirect if feature is not enabled
useEffect(() => {
if (features && !features.webhooks) {
router.push("/settings/general");
toast.error("This feature is not available for your team");
}
}, [features, router]);
const [formData, setFormData] = useState<WebhookFormData>({
name: "",
triggers: [],
});

const { data: webhook, mutate } = useSWR<Webhook>(
teamId && id ? `/api/teams/${teamId}/webhooks/${id}` : null,
Expand All @@ -63,11 +54,6 @@ export default function WebhookDetail() {
},
);

const [formData, setFormData] = useState<WebhookFormData>({
name: "",
triggers: [],
});

useEffect(() => {
if (webhook) {
setFormData({
Expand All @@ -78,6 +64,11 @@ export default function WebhookDetail() {
}, [webhook]);

const handleUpdate = async () => {
if (isFree || isPro) {
toast.error("This feature is not available on your plan");
return;
}

try {
const response = await fetch(`/api/teams/${teamId}/webhooks/${id}`, {
method: "PATCH",
Expand Down Expand Up @@ -346,7 +337,15 @@ export default function WebhookDetail() {
<div className="pt-4">
{isEditing ? (
<div className="flex gap-2">
<Button onClick={handleUpdate}>Save Changes</Button>
<Button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
handleUpdate();
}}
>
Save Changes
</Button>
<Button
variant="outline"
className="dark:bg-transparent dark:hover:bg-muted"
Expand All @@ -356,7 +355,19 @@ export default function WebhookDetail() {
</Button>
</div>
) : (
<Button onClick={() => setIsEditing(true)}>
<Button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
if (isFree || isPro) {
toast.error(
"This feature is not available on your plan",
);
return;
}
setIsEditing(true);
}}
>
Click to edit webhook
</Button>
)}
Expand Down
Loading