Skip to content
Open
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
9 changes: 6 additions & 3 deletions apps/next-main/app/app/page.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import React, {
} from "react";

import {motion} from "framer-motion";
import _lodash from "lodash";
import {
ChevronDown,
FileText,
} from "lucide-react";
import dynamic from "next/dynamic";
import {useRouter} from "next/navigation";
import posthog from "posthog-js";

Expand All @@ -31,12 +31,15 @@ import {
useTheme,
} from "@mui/material";

import VoronoiBackgroundDefault
from "../../components/backgrounds/VoronoiBackgroundDefault";
import {Footer} from "../../components/footer/Footer";
import {HomeMainSkillCreatorV2} from "../HomeMainSkillCreatorV2";
import {HomepageContinueLearning} from "../HomepageContinueLearning";

const VoronoiBackgroundDefault = dynamic(
() => import("../../components/backgrounds/VoronoiBackgroundDefault"),
{ ssr: false }
);

const AnimatedLearnMore = () => {
const durationsMs = useDurationsMs();
const theme = useTheme();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'use client'
import {ReactFlowProvider} from "reactflow";
import dynamic from "next/dynamic";

import {
Paper,
Expand All @@ -8,6 +8,11 @@ import {

import {SkillSetTree} from "../../SkillSetTree";

const ReactFlowProvider = dynamic(
() => import("reactflow").then((mod) => ({ default: mod.ReactFlowProvider })),
{ ssr: false }
);

export default function Page(){
return <div>
<Paper>
Expand Down
24 changes: 7 additions & 17 deletions apps/next-main/clientOnly/hooks/useRsnUser.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
"use client";
import {useState} from "react";

import _ from "lodash";

import {useSupabase} from "@/components/supabase/SupabaseProvider";
import {useReactiveVar} from "@apollo/client";
import {
useRsnUserFlatFragLoader,
useRsnUserSysdataFlatFragLoader,
} from "@reasonote/lib-sdk-apollo-client-react";
import {uuidv4} from "@reasonote/lib-utils";
import {useEffectDeepEqual} from "@reasonote/lib-utils-frontend";

import {useSupabaseSession} from "../../components/supabase/useSupabaseSession";
import {useSupabaseUser} from "../../components/supabase/useSupabaseUser";
Expand All @@ -22,6 +19,11 @@ interface LoginJwtResult {
has_password: boolean;
}

// Cache the timezone string to avoid repeated Intl lookups
const browserTimezone = typeof Intl !== 'undefined'
? Intl.DateTimeFormat().resolvedOptions().timeZone
: 'UTC';

export function useRsnUserId() {
const rsnUserId = useReactiveVar(rsnUserIdVar);
return rsnUserId;
Expand Down Expand Up @@ -53,7 +55,7 @@ export function useRsnUser() {
try {
console.debug('login_jwt fetchFn');
var innerJwtResult = await supabase.rpc('login_jwt', {
browser_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
browser_timezone: browserTimezone
});

if (innerJwtResult.error) {
Expand All @@ -67,7 +69,7 @@ export function useRsnUser() {
await supabase.auth.signInAnonymously();
// Refetch the jwt with the new anonymous user
innerJwtResult = await supabase.rpc('login_jwt', {
browser_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
browser_timezone: browserTimezone
});
}
else {
Expand Down Expand Up @@ -98,18 +100,6 @@ export function useRsnUser() {
currentRsnUserId ? `rsnusrsys_${currentRsnUserId?.split("_")[1]}` : undefined
);

useEffectDeepEqual(() => {
// console.debug("useRsnUser: rsnUserSysdata", rsnUserSysdata);
}, [rsnUserSysdata.data]);

useEffectDeepEqual(() => {
// console.debug("useRsnUser: rsnUser", rsnUser);
}, [rsnUser.data]);

useEffectDeepEqual(() => {
// console.debug(`${instanceId}: login_jwt useRsnUser: rsnUserId`, currentRsnUserId);
}, [currentRsnUserId]);

return {
refresh: loginJwtResult.refetch,
sbSession: session,
Expand Down
34 changes: 32 additions & 2 deletions apps/next-main/components/ClientOnly.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,42 @@
"use client";
import { useEffect, useState } from "react";

export default function ClientOnly({ children, ...delegated }: any) {
export default function ClientOnly({ children, fallback, ...delegated }: any) {
const [hasMounted, setHasMounted] = useState(false);

useEffect(() => {
setHasMounted(true);
}, []);

return hasMounted ? children : null;
if (!hasMounted) {
return fallback ?? (
<div
style={{
position: "absolute",
top: 0,
left: 0,
width: "100vw",
height: "100dvh",
display: "flex",
alignItems: "center",
justifyContent: "center",
background: "#121212",
}}
>
<div
style={{
width: 48,
height: 48,
border: "4px solid rgba(255,255,255,0.1)",
borderTopColor: "rgba(255,255,255,0.6)",
borderRadius: "50%",
animation: "rsn-spin 0.8s linear infinite",
}}
/>
<style>{`@keyframes rsn-spin { to { transform: rotate(360deg); } }`}</style>
</div>
);
}

return children;
}
93 changes: 55 additions & 38 deletions apps/next-main/components/_APP/_baseLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,8 @@ import React, {
useState,
} from "react";

////////////////////////////////////////////////////////
// When the user changes, we must update the subscription var.
import * as AsyncMutex from "async-mutex";
import {UserInteractionProvider} from "contexts/UserInteractionContext";
import _ from "lodash";
import posthog from "posthog-js";
import type PostHogType from "posthog-js";

import {AIBrowserProvider} from "@/clientOnly/ai/AIBrowserProvider";
import {BreadcrumbProvider} from "@/clientOnly/context/BreadcrumbContext";
Expand Down Expand Up @@ -107,32 +103,62 @@ function AppProviderWrapper({ children }: React.PropsWithChildren<{}>) {
});
}, [sbUrl]);

// // Create a new supabase browser client on every first render.
// const [supabaseClient] = useState(() => createBrowserSupabaseClient())
if (!apolloClient) {
// Show a lightweight loading state instead of null to avoid blank screen
return (
<div
style={{
position: "absolute",
top: 0,
left: 0,
width: "100vw",
height: "100dvh",
display: "flex",
alignItems: "center",
justifyContent: "center",
background: theme.palette.background.default,
}}
>
<div
style={{
width: 48,
height: 48,
border: `4px solid ${theme.palette.divider}`,
borderTopColor: theme.palette.primary.main,
borderRadius: "50%",
animation: "rsn-spin 0.8s linear infinite",
}}
/>
<style>{`@keyframes rsn-spin { to { transform: rotate(360deg); } }`}</style>
</div>
);
}

// Get the authToken
return apolloClient ? (
// Setup the Apollo Provider
return (
//@ts-ignore - ApolloProvider react component is not typed correctly.
<ApolloProvider client={apolloClient}>
{/* Sets up Vercel Analytics */}
<Analytics />
<RsnClientProvider>
{children}
</RsnClientProvider>
</ApolloProvider >
) : null;
</ApolloProvider>
);
}

const mutex = new AsyncMutex.Mutex();

export function UserHandling({ children }: any) {
// This will now handle all the login logic internally
useRsnUser();

return <>{children}</>;
}

// Lazily loaded posthog instance - loaded after initial render to avoid blocking
let _posthogInstance: typeof PostHogType | null = null;
function getPosthog(): typeof PostHogType | null {
return _posthogInstance;
}

export function PosthogProvider({ children }: any) {
useEffect(() => {
const token = process.env.NEXT_PUBLIC_POSTHOG_TOKEN;
Expand All @@ -144,31 +170,20 @@ export function PosthogProvider({ children }: any) {

// only if on reasonote.com do we do this, not on dev.reasonote.com or localhost, or anything else.
if (window.location.hostname === 'reasonote.com' || window.location.hostname === 'www.reasonote.com') {
posthog.init(token, {
api_host: '/posthog/ingest',
person_profiles: 'identified_only',
session_recording: {
maskAllInputs: false,
maskInputOptions: {
password: true, // Highly recommended as a minimum!!
// color: false,
// date: false,
// 'datetime-local': false,
// email: false,
// month: false,
// number: false,
// range: false,
// search: false,
// tel: false,
// text: false,
// time: false,
// url: false,
// week: false,
// textarea: false,
// select: false,
// Lazy-load posthog to keep it off the critical rendering path
import("posthog-js").then(({ default: posthog }) => {
_posthogInstance = posthog;
posthog.init(token, {
api_host: '/posthog/ingest',
person_profiles: 'identified_only',
session_recording: {
maskAllInputs: false,
maskInputOptions: {
password: true,
}
}
}
})
});
});
}
else {
console.warn("Not on reasonote.com or www.reasonote.com, skipping Posthog init");
Expand All @@ -183,6 +198,8 @@ export function PosthogProvider({ children }: any) {
const name = (rsnUser?.data?.familyName ?? "") + " " + (rsnUser?.data?.givenName ?? "");

useEffect(() => {
const posthog = getPosthog();
if (!posthog) return;
if (rsnUserId) {
posthog.identify(rsnUserId, {
email: email,
Expand Down
2 changes: 1 addition & 1 deletion apps/next-main/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
"mermaid": "10.9.0",
"micro": "^10.0.1",
"mui-markdown": "1.1.14",
"next": "14.2.0",
"next": "14.2.35",
"next-transpile-modules": "^10.0.0",
"node-fetch": "^3.3.0",
"node-html-markdown": "1.3.0",
Expand Down
Loading