mirror of
https://github.com/lukevella/rallly.git
synced 2025-08-06 09:59:00 +02:00
✨ Add more paywall triggers
This commit is contained in:
parent
9ff5d907a0
commit
0b808259ab
1 changed files with 149 additions and 127 deletions
|
@ -6,6 +6,7 @@ import {
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "@rallly/ui/card";
|
} from "@rallly/ui/card";
|
||||||
|
import { useDialog } from "@rallly/ui/dialog";
|
||||||
import { FormField } from "@rallly/ui/form";
|
import { FormField } from "@rallly/ui/form";
|
||||||
import { Switch } from "@rallly/ui/switch";
|
import { Switch } from "@rallly/ui/switch";
|
||||||
import { AtSignIcon, EyeIcon, MessageCircleIcon, VoteIcon } from "lucide-react";
|
import { AtSignIcon, EyeIcon, MessageCircleIcon, VoteIcon } from "lucide-react";
|
||||||
|
@ -13,8 +14,10 @@ import React from "react";
|
||||||
import { useFormContext } from "react-hook-form";
|
import { useFormContext } from "react-hook-form";
|
||||||
import { Trans } from "react-i18next";
|
import { Trans } from "react-i18next";
|
||||||
|
|
||||||
|
import { PayWallDialog } from "@/components/pay-wall-dialog";
|
||||||
import { ProFeatureBadge } from "@/components/pro-feature-badge";
|
import { ProFeatureBadge } from "@/components/pro-feature-badge";
|
||||||
import { usePlan } from "@/contexts/plan";
|
import { usePlan } from "@/contexts/plan";
|
||||||
|
import { usePostHog } from "@/utils/posthog";
|
||||||
|
|
||||||
export type PollSettingsFormData = {
|
export type PollSettingsFormData = {
|
||||||
requireParticipantEmail: boolean;
|
requireParticipantEmail: boolean;
|
||||||
|
@ -46,150 +49,169 @@ const SettingTitle = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Setting = ({
|
const Setting = ({ children }: React.PropsWithChildren) => {
|
||||||
children,
|
|
||||||
disabled,
|
|
||||||
}: React.PropsWithChildren<{ disabled?: boolean }>) => {
|
|
||||||
const Component = disabled ? "div" : "label";
|
|
||||||
return (
|
return (
|
||||||
<Component
|
<label
|
||||||
className={cn(
|
className={cn(
|
||||||
disabled
|
"cursor-pointer bg-white hover:bg-gray-50 active:bg-gray-100",
|
||||||
? "bg-muted-background text-muted-foreground"
|
|
||||||
: "cursor-pointer bg-white hover:bg-gray-50 active:bg-gray-100",
|
|
||||||
"flex select-none justify-between gap-x-4 gap-y-2.5 rounded-md border p-3 sm:flex-row ",
|
"flex select-none justify-between gap-x-4 gap-y-2.5 rounded-md border p-3 sm:flex-row ",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Component>
|
</label>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PollSettingsForm = ({ children }: React.PropsWithChildren) => {
|
export const PollSettingsForm = ({ children }: React.PropsWithChildren) => {
|
||||||
const form = useFormContext<PollSettingsFormData>();
|
const form = useFormContext<PollSettingsFormData>();
|
||||||
|
const posthog = usePostHog();
|
||||||
|
const paywallDialog = useDialog();
|
||||||
const plan = usePlan();
|
const plan = usePlan();
|
||||||
|
|
||||||
const isFree = plan === "free";
|
const isFree = plan === "free";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<>
|
||||||
<CardHeader>
|
<Card>
|
||||||
<div className="flex justify-between gap-x-4">
|
<CardHeader>
|
||||||
<div>
|
<div className="flex justify-between gap-x-4">
|
||||||
<div className="flex items-center gap-x-2">
|
<div>
|
||||||
<CardTitle>
|
<div className="flex items-center gap-x-2">
|
||||||
<Trans i18nKey="settings" />
|
<CardTitle>
|
||||||
</CardTitle>
|
<Trans i18nKey="settings" />
|
||||||
|
</CardTitle>
|
||||||
|
</div>
|
||||||
|
<CardDescription>
|
||||||
|
<Trans
|
||||||
|
i18nKey="pollSettingsDescription"
|
||||||
|
defaults="Customize the behaviour of your poll"
|
||||||
|
/>
|
||||||
|
</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
<CardDescription>
|
|
||||||
<Trans
|
|
||||||
i18nKey="pollSettingsDescription"
|
|
||||||
defaults="Customize the behaviour of your poll"
|
|
||||||
/>
|
|
||||||
</CardDescription>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</CardHeader>
|
||||||
</CardHeader>
|
<CardContent>
|
||||||
<CardContent>
|
<div className={cn("grid gap-2.5")}>
|
||||||
<div className={cn("grid gap-2.5")}>
|
<FormField
|
||||||
<FormField
|
control={form.control}
|
||||||
control={form.control}
|
name="disableComments"
|
||||||
name="disableComments"
|
render={({ field }) => (
|
||||||
render={({ field }) => (
|
<Setting>
|
||||||
<Setting>
|
<MessageCircleIcon className="size-5 shrink-0 translate-y-0.5" />
|
||||||
<MessageCircleIcon className="size-5 shrink-0 translate-y-0.5" />
|
<SettingContent>
|
||||||
<SettingContent>
|
<SettingTitle htmlFor="disableComments">
|
||||||
<SettingTitle htmlFor="disableComments">
|
<Trans i18nKey="disableComments">Disable Comments</Trans>
|
||||||
<Trans i18nKey="disableComments">Disable Comments</Trans>
|
</SettingTitle>
|
||||||
</SettingTitle>
|
</SettingContent>
|
||||||
</SettingContent>
|
<Switch
|
||||||
<Switch
|
id={field.name}
|
||||||
id={field.name}
|
checked={field.value}
|
||||||
checked={field.value}
|
onCheckedChange={(checked) => {
|
||||||
onCheckedChange={(checked) => {
|
field.onChange(checked);
|
||||||
field.onChange(checked);
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
</Setting>
|
||||||
</Setting>
|
)}
|
||||||
)}
|
/>
|
||||||
/>
|
<FormField
|
||||||
<FormField
|
control={form.control}
|
||||||
control={form.control}
|
name="requireParticipantEmail"
|
||||||
name="requireParticipantEmail"
|
render={({ field }) => (
|
||||||
render={({ field }) => (
|
<Setting>
|
||||||
<Setting disabled={isFree}>
|
<AtSignIcon className="size-5 shrink-0 translate-y-0.5" />
|
||||||
<AtSignIcon className="size-5 shrink-0 translate-y-0.5" />
|
<SettingContent>
|
||||||
<SettingContent>
|
<SettingTitle pro>
|
||||||
<SettingTitle pro>
|
<Trans
|
||||||
<Trans
|
i18nKey="requireParticipantEmailLabel"
|
||||||
i18nKey="requireParticipantEmailLabel"
|
defaults="Make email address required for participants"
|
||||||
defaults="Make email address required for participants"
|
/>
|
||||||
/>
|
</SettingTitle>
|
||||||
</SettingTitle>
|
</SettingContent>
|
||||||
</SettingContent>
|
<Switch
|
||||||
<Switch
|
checked={field.value}
|
||||||
disabled={isFree}
|
onCheckedChange={(checked) => {
|
||||||
checked={field.value}
|
if (isFree) {
|
||||||
onCheckedChange={(checked) => {
|
paywallDialog.trigger();
|
||||||
field.onChange(checked);
|
posthog?.capture("trigger paywall", {
|
||||||
}}
|
setting: "require-participant-email",
|
||||||
/>
|
from: "poll-settings",
|
||||||
</Setting>
|
});
|
||||||
)}
|
} else {
|
||||||
/>
|
field.onChange(checked);
|
||||||
<FormField
|
}
|
||||||
control={form.control}
|
}}
|
||||||
name="hideParticipants"
|
/>
|
||||||
render={({ field }) => (
|
</Setting>
|
||||||
<Setting disabled={isFree}>
|
)}
|
||||||
<EyeIcon className="size-5 shrink-0 translate-y-0.5" />
|
/>
|
||||||
<SettingContent>
|
<FormField
|
||||||
<SettingTitle pro>
|
control={form.control}
|
||||||
<Trans
|
name="hideParticipants"
|
||||||
i18nKey="hideParticipantsLabel"
|
render={({ field }) => (
|
||||||
defaults="Hide participants from each other"
|
<Setting>
|
||||||
/>
|
<EyeIcon className="size-5 shrink-0 translate-y-0.5" />
|
||||||
</SettingTitle>
|
<SettingContent>
|
||||||
</SettingContent>
|
<SettingTitle pro>
|
||||||
<Switch
|
<Trans
|
||||||
disabled={isFree}
|
i18nKey="hideParticipantsLabel"
|
||||||
checked={field.value}
|
defaults="Hide participants from each other"
|
||||||
onCheckedChange={(checked) => {
|
/>
|
||||||
field.onChange(checked);
|
</SettingTitle>
|
||||||
}}
|
</SettingContent>
|
||||||
/>
|
<Switch
|
||||||
</Setting>
|
checked={field.value}
|
||||||
)}
|
onCheckedChange={(checked) => {
|
||||||
/>
|
if (isFree) {
|
||||||
<FormField
|
paywallDialog.trigger();
|
||||||
control={form.control}
|
posthog?.capture("trigger paywall", {
|
||||||
name="hideScores"
|
setting: "hide-participants",
|
||||||
render={({ field }) => (
|
from: "poll-settings",
|
||||||
<Setting disabled={isFree}>
|
});
|
||||||
<VoteIcon className="size-5 shrink-0 translate-y-0.5" />
|
} else {
|
||||||
<SettingContent>
|
field.onChange(checked);
|
||||||
<SettingTitle htmlFor={field.name} pro>
|
}
|
||||||
<Trans
|
}}
|
||||||
i18nKey="hideScoresLabel"
|
/>
|
||||||
defaults="Hide scores until after a participant has voted"
|
</Setting>
|
||||||
/>
|
)}
|
||||||
</SettingTitle>
|
/>
|
||||||
</SettingContent>
|
<FormField
|
||||||
<Switch
|
control={form.control}
|
||||||
id={field.name}
|
name="hideScores"
|
||||||
disabled={isFree}
|
render={({ field }) => (
|
||||||
checked={field.value}
|
<Setting>
|
||||||
onCheckedChange={(checked) => {
|
<VoteIcon className="size-5 shrink-0 translate-y-0.5" />
|
||||||
field.onChange(checked);
|
<SettingContent>
|
||||||
}}
|
<SettingTitle htmlFor={field.name} pro>
|
||||||
/>
|
<Trans
|
||||||
</Setting>
|
i18nKey="hideScoresLabel"
|
||||||
)}
|
defaults="Hide scores until after a participant has voted"
|
||||||
/>
|
/>
|
||||||
</div>
|
</SettingTitle>
|
||||||
</CardContent>
|
</SettingContent>
|
||||||
{children}
|
<Switch
|
||||||
</Card>
|
id={field.name}
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={(checked) => {
|
||||||
|
if (isFree) {
|
||||||
|
paywallDialog.trigger();
|
||||||
|
posthog?.capture("trigger paywall", {
|
||||||
|
setting: "hide-scores",
|
||||||
|
from: "poll-settings",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
field.onChange(checked);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Setting>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
{children}
|
||||||
|
</Card>
|
||||||
|
<PayWallDialog {...paywallDialog.dialogProps} />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue