Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ NEXT_PUBLIC_MESH_SDK_KEY=<replace-with-mesh-sdk-key>
NEXT_PUBLIC_UNIFY_SCRIPT_SRC=<replace-with-unify-script-src>
NEXT_PUBLIC_UNIFY_API_KEY=<replace-with-unify-api-key>
NEXT_PUBLIC_RB2B_KEY=<replace-with-rb2b-key>
NEXT_PUBLIC_PYLON_APP_ID=<replace-with-pylon-app-id>
PYLON_IDENTITY_SECRET=<replace-with-pylon-identity-secret>

# Search mode: 'fumadocs' (default, uses Fumadocs built-in search) or 'rag' (uses RAG endpoint at mcp.superwall.com)
SEARCH_MODE=fumadocs
27 changes: 20 additions & 7 deletions content/docs/support.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,33 @@ description: "Need help with anything Superwall-related? We're here to help."

## Resources

We have lots of resources that can help you find the answer to your issue, try looking there first:
We have lots of resources that can help you find the answer to your issue:
- [Ask AI](/ai) for **instant answers** to your questions
- Consult our Docs (you're here right now! try searching for your issue)
- Search for solutions in our [Help Center](https://support.superwall.com/)
- Check our [Status Page](https://status.superwall.com/) for any on-going issues
- [Ask AI](/ai) for instant answers to your questions

## Contact Support

If additional help is required, you can contact Support by logging into your dashboard at [superwall.com](https://superwall.com/login) and using the **💬 Chat button** at the bottom-right corner of the screen.

**Please provide any relevant details to help us resolve your issue quickly:**
- A detailed description of the issue
- User IDs if the issue is affecting specific users
If additional help is required, you can create a new Support ticket by using the **💬 Support button** in the bottom-right corner of the screen.

<LoginStatusProvider>
<BasedOnAuth>
<LoggedIn>
<Info>
**Please provide all relevant details to help us resolve your issue quickly:**
- A detailed description of the issue
- User IDs if the issue is affecting specific users
- Any and all relevant screenshots, links, logs, etc.
</Info>
</LoggedIn>
<LoggedOut>
<Warning>
You will need to [log into your Superwall account](https://superwall.com/login) first
</Warning>
</LoggedOut>
</BasedOnAuth>
</LoginStatusProvider>

## Need help faster?
Try using [Ask AI](/ai) for instant answers.
50 changes: 48 additions & 2 deletions src/components/GlobalScripts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,67 @@ export function GlobalScripts({ location }: GlobalScriptsProps) {
const unifyScriptSrc = process.env.NEXT_PUBLIC_UNIFY_SCRIPT_SRC;
const unifyApiKey = process.env.NEXT_PUBLIC_UNIFY_API_KEY;
const rb2bKey = process.env.NEXT_PUBLIC_RB2B_KEY;
const pylonAppId = process.env.NEXT_PUBLIC_PYLON_APP_ID;

const scriptContent = `
(async function () {

try {
var response = await fetch('/api/auth/session', { credentials: 'include' });
var isLoggedIn = true;
var sessionData = null;
if (response && response.ok) {
try {
var session = await response.json();
isLoggedIn = !!(session && session.isLoggedIn);
sessionData = session;
} catch (_e) {
// ignore JSON parse errors; default remains logged in
console.error('Failed to authenticate user' + _e);
return;
}
}
if (!isLoggedIn) {
else {
console.error('Failed to authenticate user');
return;
}

if (isLoggedIn) {
// Load Pylon widget for logged-in users
var pylonAppId = ${toJsStringLiteral(pylonAppId)};
if (pylonAppId && sessionData.userInfo.email) {
// Load Pylon widget script
(function(){
var e=window;
var t=document;
var n=function(){n.e(arguments)};
n.q=[];
n.e=function(e){n.q.push(e)};
e.Pylon=n;
var r=function(){
var e=t.createElement("script");
e.setAttribute("type","text/javascript");
e.setAttribute("async","true");
e.setAttribute("src","https://widget.usepylon.com/widget/" + pylonAppId);
var n=t.getElementsByTagName("script")[0];
n.parentNode.insertBefore(e,n);
};
if(t.readyState==="complete"){r()}
else if(e.addEventListener){e.addEventListener("load",r,false)}
})();

// Configure Pylon with user data from session
var userEmail = sessionData.userInfo.email;
var userName = sessionData.userInfo.name;
window.pylon = {
chat_settings: {
app_id: pylonAppId,
email: sessionData.userInfo.email,
name: sessionData.userInfo.name,
email_hash: sessionData.emailHash,
}
};
}
} else {
var meshSdkKey = ${toJsStringLiteral(meshSdkKey)};
if (meshSdkKey) {
// Avina
Expand Down
139 changes: 139 additions & 0 deletions src/components/LoginStatusContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
'use client';

import React, { createContext, useContext, useEffect, useState } from 'react';
import { LoaderCircle } from 'lucide-react';

// Context for sharing login status across components
const LoginStatusContext = createContext<{
isLoggedIn: boolean | null;
isLoading: boolean;
}>({
isLoggedIn: null,
isLoading: true,
});

// Provider component that checks login status once
export function LoginStatusProvider({ children }: { children: React.ReactNode }) {
const [isLoggedIn, setIsLoggedIn] = useState<boolean | null>(null);
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
async function checkAuth() {
try {
const response = await fetch('/api/auth/session', {
credentials: 'include'
});

if (response && response.ok) {
try {
const session = await response.json();
setIsLoggedIn(!!(session && session.isLoggedIn));
} catch (_e) {
console.error('Failed to parse session data', _e);
setIsLoggedIn(false);
}
} else {
setIsLoggedIn(false);
}
} catch (_err) {
// On error, assume not logged in
setIsLoggedIn(false);
} finally {
setIsLoading(false);
}
}

checkAuth();
}, []);

return (
<LoginStatusContext.Provider value={{ isLoggedIn, isLoading }}>
{children}
</LoginStatusContext.Provider>
);
}

// Hook to use login status context
function useLoginStatus() {
return useContext(LoginStatusContext);
}

// Loading component
function LoadingState() {
return (
<p className="flex items-center gap-2 text-fd-muted-foreground">
<LoaderCircle className="size-4 animate-spin" />
Loading...
</p>
);
}

// Helper components for MDX children syntax - these handle their own conditional rendering
export function LoggedIn({ children }: { children: React.ReactNode }) {
const { isLoggedIn, isLoading } = useLoginStatus();

if (isLoading || !isLoggedIn) {
return null;
}

return <>{children}</>;
}
LoggedIn.displayName = 'LoggedIn';

export function LoggedOut({ children }: { children: React.ReactNode }) {
const { isLoggedIn, isLoading } = useLoginStatus();

if (isLoading || isLoggedIn) {
return null;
}

return <>{children}</>;
}
LoggedOut.displayName = 'LoggedOut';

// General-purpose component that conditionally renders content based on auth status
interface BasedOnAuthProps {
loggedIn?: React.ReactNode;
loggedOut?: React.ReactNode;
children?: React.ReactNode; // For MDX children syntax
}

export function BasedOnAuth({ loggedIn, loggedOut, children }: BasedOnAuthProps) {
const { isLoading } = useLoginStatus();

// Show loading state while checking
if (isLoading) {
return <LoadingState />;
}

// If children are provided, render them (LoggedIn/LoggedOut will handle their own conditional rendering)
if (children) {
return <>{children}</>;
}

// Fall back to props-based approach
const { isLoggedIn } = useLoginStatus();
return <>{isLoggedIn ? loggedIn : loggedOut}</>;
}

// Component for logged-in users (for use with children syntax)
export function WhenLoggedIn({ children }: { children: React.ReactNode }) {
const { isLoggedIn, isLoading } = useLoginStatus();

if (isLoading || !isLoggedIn) {
return null;
}

return <>{children}</>;
}

// Component for logged-out users (for use with children syntax)
export function WhenLoggedOut({ children }: { children: React.ReactNode }) {
const { isLoggedIn, isLoading } = useLoginStatus();

if (isLoading || isLoggedIn) {
return null;
}

return <>{children}</>;
}
7 changes: 7 additions & 0 deletions src/mdx-components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Accordion, Accordions as AccordionGroup } from 'fumadocs-ui/components/
import { ImageZoom as Frame } from 'fumadocs-ui/components/image-zoom'
import { SDKContent } from './components/SDKContent'
import { GithubInfo as GithubInfoComponent } from 'fumadocs-ui/components/github-info';
import { WhenLoggedIn, WhenLoggedOut, LoginStatusProvider, BasedOnAuth, LoggedIn, LoggedOut } from './components/LoginStatusContext';

// We'll add custom components here

Expand Down Expand Up @@ -278,5 +279,11 @@ export function getMDXComponents(components?: MDXComponents): MDXComponents {
SDKContent,
GithubInfo,
ParamTable,
WhenLoggedIn,
WhenLoggedOut,
LoginStatusProvider,
BasedOnAuth,
LoggedIn,
LoggedOut,
} as MDXComponents
}