feat: gated features modal (#25296)
* feat: Modal for gated features * use zustand * refactor * Apply suggestions from code review Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * Update packages/ui/components/card/Card.tsx Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * dismiss button fix and url fix * fix: broken redirect to teams * fix: type check and review comments * add learn more tracking back --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
This commit is contained in:
co-authored by
cubic-dev-ai[bot]
Udit Takkar
parent
191dcc45b5
commit
44104e1ba4
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 429 KiB |
@@ -4093,6 +4093,11 @@
|
||||
"onboarding_teams_browser_view_no_teams_title": "No teams yet",
|
||||
"onboarding_teams_browser_view_no_teams_description": "Add teams to get started",
|
||||
"book_now": "Book now",
|
||||
"only_available_on_orgs_plan": "This feature is available on the Organization plan",
|
||||
"upgrade_team_to_orgs_with_price": "Upgrade your team to get access to this and much more for $37 per month/user.",
|
||||
"attribute_based_routing": "Attribute-based routing",
|
||||
"compliance_check": "SOC2, HIPAA, ISO 27001 compliance check",
|
||||
"and_more_features": "and more features...",
|
||||
"view": "View",
|
||||
"booking_response": "Booking Response",
|
||||
"list_view": "List view",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { WelcomeToOrganizationsModal } from "@calcom/features/ee/organizations/components/WelcomeToOrganizationsModal";
|
||||
|
||||
import { WelcomeToCalcomModal } from "./components/WelcomeToCalcomModal";
|
||||
import { GatedFeaturesModal } from "./components/GatedFeaturesModal";
|
||||
|
||||
/**
|
||||
* Container for all query-param driven modals that should appear globally across the app.
|
||||
@@ -20,6 +21,7 @@ export function DynamicModals() {
|
||||
<WelcomeToOrganizationsModal />
|
||||
<WelcomeToCalcomModal />
|
||||
{/* Add more query-param driven modals here */}
|
||||
<GatedFeaturesModal />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Dialog, DialogContent } from "@calcom/ui/components/dialog";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
|
||||
import { useGatedFeaturesStore, GatedFeatures } from "../stores/gatedFeaturesStore";
|
||||
|
||||
type FeatureContent = {
|
||||
badgeText: string;
|
||||
title: string;
|
||||
image: string;
|
||||
description: string;
|
||||
features: string[];
|
||||
learnMoreUrl: string;
|
||||
ctaUrl: string;
|
||||
};
|
||||
|
||||
const content: Record<GatedFeatures, FeatureContent> = {
|
||||
roles_and_permissions: {
|
||||
badgeText: "roles_and_permissions",
|
||||
title: "only_available_on_orgs_plan",
|
||||
image: "/gated-features/roles_and_permissions.svg",
|
||||
description: "upgrade_team_to_orgs_with_price",
|
||||
features: [
|
||||
"1_parent_team_unlimited_subteams",
|
||||
"attribute_based_routing",
|
||||
"compliance_check",
|
||||
"and_more_features",
|
||||
],
|
||||
learnMoreUrl: "https://cal.com/enterprise",
|
||||
ctaUrl: "/settings/organizations/new",
|
||||
},
|
||||
};
|
||||
|
||||
export function GatedFeaturesModal() {
|
||||
const { t } = useLocale();
|
||||
const isOpen = useGatedFeaturesStore((state) => state.isOpen);
|
||||
const activeFeature = useGatedFeaturesStore((state) => state.activeFeature);
|
||||
const close = useGatedFeaturesStore((state) => state.close);
|
||||
|
||||
const data = activeFeature ? content[activeFeature] : null;
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { badgeText, description, image, title, features, learnMoreUrl, ctaUrl } = data;
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={(open) => !open && close()}>
|
||||
<DialogContent className="p-0!" style={{ maxWidth: "400px" }}>
|
||||
<div className="p-6">
|
||||
<img src={image} alt={t(title)} className="w-full h-36 mb-5" />
|
||||
<div className="p-1 text-xs bg-emphasis rounded-md w-fit mb-3 leading-3">{t(badgeText)}</div>
|
||||
|
||||
<div className="mb-5 flex flex-col gap-2">
|
||||
<div className="text-xl font-semibold text-emphasis leading-6">{t(title)}</div>
|
||||
<div className="text-sm leading-5 font-normal text-default">{t(description)}</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1 ml-6">
|
||||
<ul className="list-disc">
|
||||
{features.map((feature) => (
|
||||
<li className="text-sm text-default font-medium" key={feature}>{t(feature)}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full bg-muted border-subtle flex items-center justify-between rounded-b-2xl border-t px-6 py-5">
|
||||
<Button color="minimal" onClick={close}>{t("dismiss")}</Button>
|
||||
<div className="flex gap-2">
|
||||
<Button color="secondary" target="_blank" rel="noopener noreferrer" href={learnMoreUrl}>{t("learn_more")}</Button>
|
||||
<Button color="primary" href={ctaUrl}>{t("upgrade")}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { create } from "zustand";
|
||||
|
||||
export enum GatedFeatures {
|
||||
RolesAndPermissions = "roles_and_permissions",
|
||||
}
|
||||
|
||||
type GatedFeaturesStore = {
|
||||
isOpen: boolean;
|
||||
activeFeature: GatedFeatures | null;
|
||||
open: (feature: GatedFeatures) => void;
|
||||
close: () => void;
|
||||
};
|
||||
|
||||
export const useGatedFeaturesStore = create<GatedFeaturesStore>((set) => ({
|
||||
isOpen: false,
|
||||
activeFeature: null,
|
||||
open: (feature) => set({ isOpen: true, activeFeature: feature }),
|
||||
close: () => set({ isOpen: false, activeFeature: null }),
|
||||
}));
|
||||
+169
-155
@@ -6,6 +6,8 @@ import posthog from "posthog-js";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { localStorage } from "@calcom/lib/webstorage";
|
||||
import { Card } from "@calcom/ui/components/card";
|
||||
import { GatedFeatures } from "@calcom/features/shell/stores/gatedFeaturesStore";
|
||||
import { useGatedFeaturesStore } from "@calcom/features/shell/stores/gatedFeaturesStore";
|
||||
|
||||
type Tip = {
|
||||
id: number;
|
||||
@@ -13,154 +15,164 @@ type Tip = {
|
||||
mediaLink?: string;
|
||||
title: string;
|
||||
description: string;
|
||||
href: string;
|
||||
href?: string;
|
||||
onClick?: () => void;
|
||||
coverPhoto?: string;
|
||||
variant?: "SidebarCard" | "NewLaunchSidebarCard";
|
||||
};
|
||||
|
||||
export const tips: Tip[] = [
|
||||
{
|
||||
id: 17,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/fMHW6jYPIb8/0.jpg",
|
||||
mediaLink: "https://go.cal.com/embed-video",
|
||||
title: "Embed",
|
||||
description: "Embed your booking page on your website",
|
||||
href: "https://go.cal.com/embed-video",
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/xopxmk2H4Ng/0.jpg",
|
||||
mediaLink: "https://go.cal.com/paid-booking",
|
||||
title: "Paid Bookings",
|
||||
description: "Charge for your time with Cal.com's paid bookings",
|
||||
href: "https://go.cal.com/paid-booking",
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/ZjSD1yPgLLQ/0.jpg",
|
||||
mediaLink: "https://go.cal.com/instant-meetings-video",
|
||||
title: "Instant Meetings",
|
||||
description: "Book meetings instantly with a link",
|
||||
href: "https://go.cal.com/instant-meetings-video",
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/IZ4-nUiIpvY/0.jpg",
|
||||
mediaLink: "https://go.cal.com/custom-attributes",
|
||||
title: "Custom Attributes",
|
||||
description: "Define roles and attributes for your teams",
|
||||
href: "https://go.cal.com/custom-attributes",
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/TTAASLLPKk0/0.jpg",
|
||||
mediaLink: "https://go.cal.com/ooo-video",
|
||||
title: "ooo.new",
|
||||
description: "Easily go out-of-office",
|
||||
href: "https://go.cal.com/ooo-video",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
thumbnailUrl: "https://cal.com/og-image-cal-ai.jpg",
|
||||
mediaLink: "https://go.cal.com/cal-ai",
|
||||
title: "Cal.ai",
|
||||
description: "Your personal AI scheduling assistant",
|
||||
href: "https://go.cal.com/cal-ai",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/KTg_qzA9NEc/0.jpg",
|
||||
mediaLink: "https://go.cal.com/insights",
|
||||
title: "Insights",
|
||||
description: "Get a better understanding of your business",
|
||||
href: "https://go.cal.com/insights",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/jvaBafzVUQc/0.jpg",
|
||||
mediaLink: "https://go.cal.com/video",
|
||||
title: "Cal Video",
|
||||
description: "Free video conferencing with recording",
|
||||
href: "https://go.cal.com/video",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/93iOmzHieCU/0.jpg",
|
||||
mediaLink: "https://go.cal.com/round-robin",
|
||||
title: "Round-Robin",
|
||||
description: "Create advanced group meetings with round-robin",
|
||||
href: "https://go.cal.com/round-robin",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/piKlAiibAFo/0.jpg",
|
||||
mediaLink: "https://go.cal.com/workflows",
|
||||
title: "Automate Workflows",
|
||||
description: "Make time work for you and automate tasks",
|
||||
href: "https://go.cal.com/workflows",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/UVXgo12cY4g/0.jpg",
|
||||
mediaLink: "https://go.cal.com/routing-forms",
|
||||
title: "Routing Forms",
|
||||
description: "Ask questions and route to the correct person",
|
||||
href: "https://go.cal.com/routing-forms",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/yGiZo1Ry5-8/0.jpg",
|
||||
mediaLink: "https://go.cal.com/recurring-video",
|
||||
title: "Recurring Bookings",
|
||||
description: "Learn how to create a recurring schedule",
|
||||
href: "https://go.cal.com/recurring-video",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/0v_nQtpxC_4/0.jpg",
|
||||
mediaLink: "https://go.cal.com/payments-video",
|
||||
title: "Accept Payments",
|
||||
description: "Charge for your time with Cal.com's Stripe App",
|
||||
href: "https://app.cal.com/apps/stripe",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/zGr_s-fG84k/0.jpg",
|
||||
mediaLink: "https://go.cal.com/confirmation-video",
|
||||
title: "Requires Confirmation",
|
||||
description: "Learn how to be in charge of your bookings",
|
||||
href: "https://cal.com/resources/feature/opt-in",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/-L8MCiT6uhQ/0.jpg",
|
||||
mediaLink: "https://youtu.be/-L8MCiT6uhQ?si=DRJzRNhN85hqAwBl",
|
||||
title: "Routing Forms, Workflows",
|
||||
description: "Ask screening questions of potential bookers to connect them with the right person",
|
||||
href: "https://youtu.be/-L8MCiT6uhQ?si=DRJzRNhN85hqAwBl",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/EAc46SPL6iA/0.jpg",
|
||||
mediaLink: "https://go.cal.com/teams-video",
|
||||
title: "How to set up Teams",
|
||||
description: "Learn how to use round-robin and collective events.",
|
||||
href: "https://cal.com/docs/enterprise-features/teams",
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/VZ5PfQzzxBw/0.jpg",
|
||||
mediaLink: "https://youtu.be/VZ5PfQzzxBw?si=oB0LPSxG8dWIwg5a",
|
||||
title: "Dynamic booking links",
|
||||
description: "Booking link that allows people to quickly schedule meetings.",
|
||||
href: "https://youtu.be/VZ5PfQzzxBw?si=oB0LPSxG8dWIwg5a",
|
||||
},
|
||||
];
|
||||
|
||||
const reversedTips = [...shuffle(tips).slice(0).reverse()];
|
||||
|
||||
function Tips() {
|
||||
const { t } = useLocale();
|
||||
const openModal = useGatedFeaturesStore((state) => state.open);
|
||||
|
||||
const tips: Tip[] = [
|
||||
{
|
||||
id: 18,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/J8HsK-8W39U/0.jpg",
|
||||
mediaLink: "https://go.cal.com/rbac-video",
|
||||
title: "Roles & Permissions",
|
||||
description: "Manage team access with roles & permissions",
|
||||
onClick: () => openModal(GatedFeatures.RolesAndPermissions),
|
||||
},
|
||||
{
|
||||
id: 17,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/fMHW6jYPIb8/0.jpg",
|
||||
mediaLink: "https://go.cal.com/embed-video",
|
||||
title: "Embed",
|
||||
description: "Embed your booking page on your website",
|
||||
href: "https://go.cal.com/embed-video",
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/xopxmk2H4Ng/0.jpg",
|
||||
mediaLink: "https://go.cal.com/paid-booking",
|
||||
title: "Paid Bookings",
|
||||
description: "Charge for your time with Cal.com's paid bookings",
|
||||
href: "https://go.cal.com/paid-booking",
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/ZjSD1yPgLLQ/0.jpg",
|
||||
mediaLink: "https://go.cal.com/instant-meetings-video",
|
||||
title: "Instant Meetings",
|
||||
description: "Book meetings instantly with a link",
|
||||
href: "https://go.cal.com/instant-meetings-video",
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/IZ4-nUiIpvY/0.jpg",
|
||||
mediaLink: "https://go.cal.com/custom-attributes",
|
||||
title: "Custom Attributes",
|
||||
description: "Define roles and attributes for your teams",
|
||||
href: "https://go.cal.com/custom-attributes",
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/TTAASLLPKk0/0.jpg",
|
||||
mediaLink: "https://go.cal.com/ooo-video",
|
||||
title: "ooo.new",
|
||||
description: "Easily go out-of-office",
|
||||
href: "https://go.cal.com/ooo-video",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
thumbnailUrl: "https://cal.com/og-image-cal-ai.jpg",
|
||||
mediaLink: "https://go.cal.com/cal-ai",
|
||||
title: "Cal.ai",
|
||||
description: "Your personal AI scheduling assistant",
|
||||
href: "https://go.cal.com/cal-ai",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/KTg_qzA9NEc/0.jpg",
|
||||
mediaLink: "https://go.cal.com/insights",
|
||||
title: "Insights",
|
||||
description: "Get a better understanding of your business",
|
||||
href: "https://go.cal.com/insights",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/jvaBafzVUQc/0.jpg",
|
||||
mediaLink: "https://go.cal.com/video",
|
||||
title: "Cal Video",
|
||||
description: "Free video conferencing with recording",
|
||||
href: "https://go.cal.com/video",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/93iOmzHieCU/0.jpg",
|
||||
mediaLink: "https://go.cal.com/round-robin",
|
||||
title: "Round-Robin",
|
||||
description: "Create advanced group meetings with round-robin",
|
||||
href: "https://go.cal.com/round-robin",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/piKlAiibAFo/0.jpg",
|
||||
mediaLink: "https://go.cal.com/workflows",
|
||||
title: "Automate Workflows",
|
||||
description: "Make time work for you and automate tasks",
|
||||
href: "https://go.cal.com/workflows",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/UVXgo12cY4g/0.jpg",
|
||||
mediaLink: "https://go.cal.com/routing-forms",
|
||||
title: "Routing Forms",
|
||||
description: "Ask questions and route to the correct person",
|
||||
href: "https://go.cal.com/routing-forms",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/yGiZo1Ry5-8/0.jpg",
|
||||
mediaLink: "https://go.cal.com/recurring-video",
|
||||
title: "Recurring Bookings",
|
||||
description: "Learn how to create a recurring schedule",
|
||||
href: "https://go.cal.com/recurring-video",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/0v_nQtpxC_4/0.jpg",
|
||||
mediaLink: "https://go.cal.com/payments-video",
|
||||
title: "Accept Payments",
|
||||
description: "Charge for your time with Cal.com's Stripe App",
|
||||
href: "https://app.cal.com/apps/stripe",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/zGr_s-fG84k/0.jpg",
|
||||
mediaLink: "https://go.cal.com/confirmation-video",
|
||||
title: "Requires Confirmation",
|
||||
description: "Learn how to be in charge of your bookings",
|
||||
href: "https://cal.com/resources/feature/opt-in",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/-L8MCiT6uhQ/0.jpg",
|
||||
mediaLink: "https://youtu.be/-L8MCiT6uhQ?si=DRJzRNhN85hqAwBl",
|
||||
title: "Routing Forms, Workflows",
|
||||
description: "Ask screening questions of potential bookers to connect them with the right person",
|
||||
href: "https://youtu.be/-L8MCiT6uhQ?si=DRJzRNhN85hqAwBl",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/EAc46SPL6iA/0.jpg",
|
||||
mediaLink: "https://go.cal.com/teams-video",
|
||||
title: "How to set up Teams",
|
||||
description: "Learn how to use round-robin and collective events.",
|
||||
href: "https://cal.com/teams",
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
thumbnailUrl: "https://img.youtube.com/vi/VZ5PfQzzxBw/0.jpg",
|
||||
mediaLink: "https://youtu.be/VZ5PfQzzxBw?si=oB0LPSxG8dWIwg5a",
|
||||
title: "Dynamic booking links",
|
||||
description: "Booking link that allows people to quickly schedule meetings.",
|
||||
href: "https://youtu.be/VZ5PfQzzxBw?si=oB0LPSxG8dWIwg5a",
|
||||
},
|
||||
];
|
||||
|
||||
const reversedTips = [...shuffle(tips).slice(0).reverse()];
|
||||
|
||||
const [list, setList] = useState<Tip[]>(() => {
|
||||
if (typeof window === "undefined") {
|
||||
@@ -230,8 +242,9 @@ function Tips() {
|
||||
mediaLinkOnClick={
|
||||
isTopTip
|
||||
? () => {
|
||||
posthog.capture("tip_video_clicked", tip);
|
||||
}
|
||||
posthog.capture("tip_video_clicked", tip);
|
||||
if (tip.onClick) tip.onClick();
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
title={t(tip.title)}
|
||||
@@ -239,23 +252,24 @@ function Tips() {
|
||||
learnMore={
|
||||
isTopTip
|
||||
? {
|
||||
href: tip.href,
|
||||
text: t("learn_more"),
|
||||
onClick: () => {
|
||||
posthog.capture("tip_learn_more_clicked", tip);
|
||||
},
|
||||
href: tip.href,
|
||||
text: t("learn_more"),
|
||||
onClick: () => {
|
||||
posthog.capture("tip_learn_more_clicked", tip);
|
||||
if (tip.onClick) tip.onClick();
|
||||
}
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
actionButton={
|
||||
isTopTip
|
||||
? {
|
||||
onClick: () => {
|
||||
posthog.capture("tip_dismiss_clicked", tip);
|
||||
handleRemoveItem(tip.id);
|
||||
},
|
||||
child: t("dismiss"),
|
||||
}
|
||||
onClick: () => {
|
||||
posthog.capture("tip_dismiss_clicked", tip);
|
||||
handleRemoveItem(tip.id);
|
||||
},
|
||||
child: t("dismiss"),
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
containerProps={{
|
||||
|
||||
@@ -133,9 +133,9 @@ export interface BaseCardProps extends CVACardType {
|
||||
"data-testid"?: string;
|
||||
};
|
||||
learnMore?: {
|
||||
href: string;
|
||||
href?: string;
|
||||
text: string;
|
||||
onClick?: (event: React.MouseEvent<HTMLAnchorElement>) => void;
|
||||
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
||||
};
|
||||
mediaLink?: string;
|
||||
mediaLinkOnClick?: (event: React.MouseEvent<HTMLAnchorElement>) => void;
|
||||
@@ -161,7 +161,7 @@ export function Card({
|
||||
buttonClassName,
|
||||
mediaLinkOnClick,
|
||||
}: BaseCardProps) {
|
||||
const LinkComponent = learnMore && learnMore.href.startsWith("https") ? "a" : Link;
|
||||
const LinkComponent = learnMore?.href?.startsWith("https") ? "a" : Link;
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
@@ -252,19 +252,30 @@ export function Card({
|
||||
{(variant === "SidebarCard" || variant === "NewLaunchSidebarCard") && (
|
||||
<div className="mt-2 flex items-center justify-between">
|
||||
{learnMore && (
|
||||
<LinkComponent
|
||||
href={learnMore.href}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
onClick={learnMore.onClick}
|
||||
className={classNames("text-default text-xs font-medium", buttonClassName)}>
|
||||
{learnMore.text}
|
||||
</LinkComponent>
|
||||
<>
|
||||
{learnMore.href ? (
|
||||
<LinkComponent
|
||||
href={learnMore.href}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
onClick={learnMore.onClick}
|
||||
className={classNames("text-default text-xs font-medium cursor-pointer", buttonClassName)}>
|
||||
{learnMore.text}
|
||||
</LinkComponent>
|
||||
) : learnMore.onClick ? (
|
||||
<button type="button"
|
||||
color="minimal"
|
||||
onClick={learnMore.onClick}
|
||||
className={classNames("cursor-pointer text-default text-xs font-medium", buttonClassName)}>
|
||||
{learnMore.text}
|
||||
</button>
|
||||
) : undefined}
|
||||
</>
|
||||
)}
|
||||
{actionButton?.child && (
|
||||
<button
|
||||
className={classNames(
|
||||
"text-default hover:text-emphasis p-0 text-xs font-normal",
|
||||
"text-default hover:text-emphasis p-0 text-xs font-normal cursor-pointer",
|
||||
buttonClassName
|
||||
)}
|
||||
color="minimal"
|
||||
|
||||
Reference in New Issue
Block a user