)
return null;
};
+
+function HelpfulInfoHasTasks({ onClose }: { onClose: () => void }) {
+ const organization = useOrganization();
+ const project = useProject();
+ const [isVideoDialogOpen, setIsVideoDialogOpen] = useState(false);
+
+ return (
+
+
+
+
+
+ Helpful next steps
+
+
+
+
}
+ />
+
}
+ />
+
setIsVideoDialogOpen(true)}
+ className={cn(
+ "group flex w-full items-center justify-between gap-2 rounded-md p-1 pr-3 transition hover:bg-charcoal-750",
+ variants["withIcon"].container
+ )}
+ >
+
+
+
+
+
+ Watch a 14 min walkthrough video
+
+
+
+
+
}
+ isExternal
+ />
+
+
+
+ From the docs
+
+
+
+
+
+
+
+
+
+
+ Example tasks
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+const variants = {
+ withIcon: {
+ container: "",
+ iconContainer:
+ "grid size-9 min-w-9 place-items-center rounded border border-transparent bg-charcoal-750 shadow transition group-hover:border-charcoal-650",
+ },
+ minimal: {
+ container: "pl-3 py-2",
+ iconContainer: "",
+ },
+} as const;
+
+type LinkWithIconProps = {
+ to: string;
+ description: string;
+ icon?: React.ReactNode;
+ isExternal?: boolean;
+ variant?: keyof typeof variants;
+};
+
+function LinkWithIcon({
+ to,
+ description,
+ icon,
+ isExternal,
+ variant = "minimal",
+}: LinkWithIconProps) {
+ const variation = variants[variant];
+
+ return (
+
+
+ {variant === "withIcon" && icon &&
{icon}
}
+
+ {description}
+
+
+
+
+ );
+}
diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.schedules.$scheduleParam/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.schedules.$scheduleParam/route.tsx
index 788795ddf3..a246a32ab3 100644
--- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.schedules.$scheduleParam/route.tsx
+++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.schedules.$scheduleParam/route.tsx
@@ -216,9 +216,10 @@ export default function Page() {
{schedule.friendlyId}
diff --git a/apps/webapp/app/services/preferences/uiPreferences.server.ts b/apps/webapp/app/services/preferences/uiPreferences.server.ts
new file mode 100644
index 0000000000..5389c5d5fd
--- /dev/null
+++ b/apps/webapp/app/services/preferences/uiPreferences.server.ts
@@ -0,0 +1,29 @@
+import { createCookieSessionStorage } from "@remix-run/node";
+import { env } from "~/env.server";
+
+export const uiPreferencesStorage = createCookieSessionStorage({
+ cookie: {
+ name: "__ui_prefs",
+ sameSite: "lax",
+ path: "/",
+ httpOnly: true,
+ secrets: [env.SESSION_SECRET],
+ secure: env.NODE_ENV === "production",
+ maxAge: 60 * 60 * 24 * 365, // 1 year
+ },
+});
+
+export function getUiPreferencesSession(request: Request) {
+ return uiPreferencesStorage.getSession(request.headers.get("Cookie"));
+}
+
+export async function getUsefulLinksPreference(request: Request): Promise {
+ const session = await getUiPreferencesSession(request);
+ return session.get("showUsefulLinks");
+}
+
+export async function setUsefulLinksPreference(show: boolean, request: Request) {
+ const session = await getUiPreferencesSession(request);
+ session.set("showUsefulLinks", show);
+ return session;
+}