📓 Add changelog widget (#798)

This commit is contained in:
Luke Vella 2023-08-02 18:30:10 +01:00 committed by GitHub
parent bc53e97f93
commit d08ed6d0f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 158 additions and 100 deletions

5
.gitignore vendored
View file

@ -35,4 +35,7 @@ yarn-error.log*
tsconfig.tsbuildinfo
# Turbo
.turbo
.turbo
# Jetbrains IDE
.idea

View file

@ -33,10 +33,6 @@ declare global {
* Crisp website ID
*/
NEXT_PUBLIC_CRISP_WEBSITE_ID?: string;
/**
* When defined users will be able to send feedback to this email address
*/
NEXT_PUBLIC_FEEDBACK_EMAIL?: string;
/**
* Users of your instance will see this as their support email
*/

View file

@ -34,9 +34,9 @@ declare global {
*/
NEXT_PUBLIC_CRISP_WEBSITE_ID?: string;
/**
* When defined users will be able to send feedback to this email address
* When `true` it will show the feedback button and pull the changelog from featurebase
*/
NEXT_PUBLIC_FEEDBACK_EMAIL?: string;
NEXT_PUBLIC_FEEDBACK_ENABLED?: string;
/**
* Users of your instance will see this as their support email
*/

View file

@ -121,7 +121,6 @@
"inviteLink": "Invite Link",
"inviteParticipantLinkInfo": "Anyone with this link will be able to vote on your poll.",
"support": "Support",
"changelog": "Change log",
"billing": "Billing",
"guestPollAlertDescription": "<0>Create an account</0> or <1>login</1> to claim this poll.",
"guestPollAlertTitle": "Your administrator rights can be lost if you clear your cookies",
@ -209,5 +208,6 @@
"clockPreferencesDescription": "Set your preferred time zone and time format.",
"featureRequest": "Request a Feature",
"bugReport": "Report an Issue",
"getSupport": "Get Support"
"getSupport": "Get Support",
"feedback": "Feedback"
}

View file

@ -1,22 +1,74 @@
import { trpc } from "@rallly/backend";
import { HelpCircleIcon } from "@rallly/icons";
import { cn } from "@rallly/ui";
import { Button } from "@rallly/ui/button";
import Script from "next/script";
import React from "react";
import { useUser } from "@/components/user-provider";
import { Trans } from "@/components/trans";
import { isFeedbackEnabled } from "@/utils/constants";
export const FeaturebaseProvider = ({ children }: React.PropsWithChildren) => {
const { user } = useUser();
const FeaturebaseScript = () => (
<Script src="https://do.featurebase.app/js/sdk.js" id="featurebase-sdk" />
);
export const Changelog = ({ className }: { className?: string }) => {
React.useEffect(() => {
if (user.isGuest) return;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const win = window as any;
if (typeof win.Featurebase !== "function") {
win.Featurebase = function (...args: unknown[]) {
(win.Featurebase.q = win.Featurebase.q || []).push(args);
};
}
win.Featurebase("initialize_changelog_widget", {
organization: "rallly", // Replace this with your featurebase organization name
placement: "bottom", // Choose between right, left, top, bottom placement
theme: "light", // Choose between dark or light theme
});
}, []);
if (!isFeedbackEnabled) return null;
return (
<>
<FeaturebaseScript />
<Button
className={cn("[&>*]:pointer-events-none", className)}
size="sm"
variant="ghost"
data-featurebase-changelog
>
<HelpCircleIcon className="h-4 w-4" />
<span className="hidden sm:block">
<Trans key="whatsNew" defaults="What's new?" />
</span>
<span
id="fb-update-badge"
className="bg-primary rounded-md px-1 py-px text-xs text-gray-100 empty:hidden"
/>
</Button>
</>
);
};
export const FeaturebaseIdentify = () => {
const { data: user } = trpc.whoami.get.useQuery();
React.useEffect(() => {
if (user?.isGuest !== false || !isFeedbackEnabled) return;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const win = window as any;
if (typeof win.Featurebase !== "function") {
win.Featurebase = function () {
// eslint-disable-next-line prefer-rest-params
(win.Featurebase.q = win.Featurebase.q || []).push(arguments);
};
}
win.Featurebase(
"identify",
{
@ -35,10 +87,6 @@ export const FeaturebaseProvider = ({ children }: React.PropsWithChildren) => {
},
);
}, [user]);
return (
<>
<Script src="https://do.featurebase.app/js/sdk.js" id="featurebase-sdk" />
{children}
</>
);
return <FeaturebaseScript />;
};

View file

@ -16,60 +16,53 @@ import {
import Link from "next/link";
import { Trans } from "next-i18next";
import { FeaturebaseProvider } from "@/components/featurebase";
const FeedbackButton = () => {
return (
<FeaturebaseProvider>
<DropdownMenu modal={false}>
<DropdownMenuTrigger className="shadow-huge fixed bottom-8 right-6 hidden h-12 w-12 items-center justify-center rounded-full bg-gray-800 hover:bg-gray-700 active:shadow-none sm:inline-flex">
<MegaphoneIcon className="h-5 text-white" />
</DropdownMenuTrigger>
<DropdownMenuContent sideOffset={10} align="end">
<DropdownMenuLabel>
<Trans i18nKey="menu" />
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem asChild>
<Link
href={`https://rallly.featurebase.app/?b=feedback`}
target={"_blank"}
>
<SmileIcon className="mr-2 h-4 w-4" />
<Trans i18nKey="sendFeedback" defaults="Send Feedback" />
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link
href={`https://rallly.featurebase.app/?b=feature-request`}
target={"_blank"}
>
<LightbulbIcon className="mr-2 h-4 w-4" />
<Trans
i18nKey={"featureRequest"}
defaults={"Request a Feature"}
/>
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link
href={`https://rallly.featurebase.app/?b=bug-reports`}
target={"_blank"}
>
<BugIcon className="mr-2 h-4 w-4" />
<Trans i18nKey={"bugReport"} defaults={"Report an Issue"} />
</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem asChild>
<Link href={`https://support.rallly.co`} target={"_blank"}>
<LifeBuoyIcon className="mr-2 h-4 w-4" />
<Trans i18nKey={"getSupport"} defaults={"Get Support"} />
</Link>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</FeaturebaseProvider>
<DropdownMenu modal={false}>
<DropdownMenuTrigger className="shadow-huge fixed bottom-8 right-6 hidden h-12 w-12 items-center justify-center rounded-full bg-gray-800 hover:bg-gray-700 active:shadow-none sm:inline-flex">
<MegaphoneIcon className="h-5 text-white" />
</DropdownMenuTrigger>
<DropdownMenuContent sideOffset={10} align="end">
<DropdownMenuLabel>
<Trans i18nKey="menu" />
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem asChild>
<Link
href={`https://rallly.featurebase.app/?b=feedback`}
target={"_blank"}
>
<SmileIcon className="mr-2 h-4 w-4" />
<Trans i18nKey="sendFeedback" defaults="Send Feedback" />
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link
href={`https://rallly.featurebase.app/?b=feature-request`}
target={"_blank"}
>
<LightbulbIcon className="mr-2 h-4 w-4" />
<Trans i18nKey={"featureRequest"} defaults={"Request a Feature"} />
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link
href={`https://rallly.featurebase.app/?b=bug-reports`}
target={"_blank"}
>
<BugIcon className="mr-2 h-4 w-4" />
<Trans i18nKey={"bugReport"} defaults={"Report an Issue"} />
</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem asChild>
<Link href={`https://support.rallly.co`} target={"_blank"}>
<LifeBuoyIcon className="mr-2 h-4 w-4" />
<Trans i18nKey={"getSupport"} defaults={"Get Support"} />
</Link>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
};

View file

@ -1,5 +1,3 @@
import "react-big-calendar/lib/css/react-big-calendar.css";
import { XIcon } from "@rallly/icons";
import dayjs from "dayjs";
import React from "react";

View file

@ -11,14 +11,16 @@ import { Toaster } from "react-hot-toast";
import { Clock, ClockPreferences } from "@/components/clock";
import { Container } from "@/components/container";
import { Changelog, FeaturebaseIdentify } from "@/components/featurebase";
import FeedbackButton from "@/components/feedback";
import { Spinner } from "@/components/spinner";
import { Trans } from "@/components/trans";
import { UserDropdown } from "@/components/user-dropdown";
import { isFeedbackEnabled } from "@/utils/constants";
import { IconComponent, NextPageWithLayout } from "../../types";
import ModalProvider from "../modal/modal-provider";
import { IfGuest, UserProvider } from "../user-provider";
import { IfGuest } from "../user-provider";
const NavMenuItem = ({
href,
@ -35,12 +37,11 @@ const NavMenuItem = ({
}) => {
const router = useRouter();
return (
<Button variant="ghost" asChild>
<Button variant="ghost" size="sm" asChild>
<Link
target={target}
href={href}
className={cn(
"flex items-center gap-2.5 px-2.5 py-1.5 text-sm font-medium",
router.asPath === href
? "text-foreground"
: "text-muted-foreground hover:text-foreground active:bg-gray-200/50",
@ -119,17 +120,23 @@ const MainNav = () => {
</nav>
</div>
<div className="flex items-center gap-x-4">
<nav className="flex gap-x-2">
<nav className="flex items-center gap-x-1 sm:gap-x-2">
<IfGuest>
<NavMenuItem
<Button
size="sm"
variant="ghost"
asChild
className="hidden sm:flex"
icon={LogInIcon}
href="/login"
label={<Trans i18nKey="login" defaults="Login" />}
/>
>
<Link href="/login">
<LogInIcon className="h-4 w-4" />
<Trans i18nKey="login" defaults="Login" />
</Link>
</Button>
</IfGuest>
<Changelog />
<ClockPreferences>
<Button className="text-muted-foreground" variant="ghost">
<Button size="sm" variant="ghost">
<Clock />
</Button>
</ClockPreferences>
@ -146,8 +153,9 @@ export const StandardLayout: React.FunctionComponent<{
hideNav?: boolean;
}> = ({ children, hideNav, ...rest }) => {
const key = hideNav ? "no-nav" : "nav";
return (
<UserProvider>
<>
<Toaster />
<ModalProvider>
<div className="flex min-h-screen flex-col" {...rest}>
@ -169,9 +177,14 @@ export const StandardLayout: React.FunctionComponent<{
</m.div>
</AnimatePresence>
</div>
{process.env.NEXT_PUBLIC_FEEDBACK_EMAIL ? <FeedbackButton /> : null}
{isFeedbackEnabled ? (
<>
<FeaturebaseIdentify />
<FeedbackButton />
</>
) : null}
</ModalProvider>
</UserProvider>
</>
);
};

View file

@ -6,8 +6,8 @@ import {
ListIcon,
LogInIcon,
LogOutIcon,
MegaphoneIcon,
RefreshCcwIcon,
ScrollTextIcon,
Settings2Icon,
UserIcon,
UserPlusIcon,
@ -26,6 +26,7 @@ import Link from "next/link";
import { Trans } from "@/components/trans";
import { CurrentUserAvatar } from "@/components/user";
import { isFeedbackEnabled } from "@/utils/constants";
import { IfAuthenticated, IfGuest, useUser } from "./user-provider";
@ -121,16 +122,18 @@ export const UserDropdown = () => {
<Trans i18nKey="support" defaults="Support" />
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild={true}>
<Link
target="_blank"
href="https://rallly.co/blog"
className="flex items-center gap-x-2"
>
<ScrollTextIcon className="h-4 w-4" />
<Trans i18nKey="changelog" defaults="Change log" />
</Link>
</DropdownMenuItem>
{isFeedbackEnabled ? (
<DropdownMenuItem asChild={true}>
<Link
target="_blank"
href="https://rallly.featurebase.app"
className="flex items-center gap-x-2"
>
<MegaphoneIcon className="h-4 w-4" />
<Trans i18nKey="feedback" defaults="Feedback" />
</Link>
</DropdownMenuItem>
) : null}
<DropdownMenuSeparator />
<IfGuest>
<DropdownMenuItem asChild={true}>

View file

@ -158,6 +158,7 @@
}
}
.rbc-time-view {
@apply border-0 border-b border-t border-gray-100;
}

View file

@ -3,3 +3,6 @@ export const plusPlanIdMonthly = process.env
export const plusPlanIdYearly = process.env
.NEXT_PUBLIC_PRO_PLAN_ID_MONTHLY as string;
export const isFeedbackEnabled =
process.env.NEXT_PUBLIC_FEEDBACK_ENABLED === "true";

View file

@ -36,7 +36,7 @@ declare global {
/**
* When defined users will be able to send feedback to this email address
*/
NEXT_PUBLIC_FEEDBACK_EMAIL?: string;
NEXT_PUBLIC_FEEDBACK_ENABLED?: string;
/**
* Users of your instance will see this as their support email
*/

View file

@ -23,7 +23,7 @@ const buttonVariants = cva(
},
size: {
default: "h-9 px-2.5 text-sm",
sm: "h-7 text-xs px-2 rounded-md",
sm: "h-7 text-xs px-1.5 rounded-md",
lg: "h-11 text-base px-4 rounded-md",
},
},

View file

@ -66,7 +66,7 @@
"NEXT_PUBLIC_CRISP_WEBSITE_ID",
"NEXT_PUBLIC_ENABLE_ANALYTICS",
"NEXT_PUBLIC_ENABLE_FINALIZATION",
"NEXT_PUBLIC_FEEDBACK_EMAIL",
"NEXT_PUBLIC_FEEDBACK_ENABLED",
"NEXT_PUBLIC_LANDING_PAGE_URL",
"NEXT_PUBLIC_MAINTENANCE_MODE",
"NEXT_PUBLIC_PADDLE_SANDBOX",