Add mobile unsupported splash screne

This commit is contained in:
bkellam 2025-02-27 16:10:55 -08:00
parent 7ce10672e1
commit b9352345a3
8 changed files with 84 additions and 13 deletions

View file

@ -118,6 +118,7 @@
"pretty-bytes": "^6.1.1",
"psl": "^1.15.0",
"react": "^18",
"react-device-detect": "^2.2.3",
"react-dom": "^18",
"react-hook-form": "^7.53.0",
"react-hotkeys-hook": "^4.5.1",

View file

@ -15,7 +15,7 @@ import { GithubConnectionConfig, GitlabConnectionConfig, GiteaConnectionConfig,
import { encrypt } from "@sourcebot/crypto"
import { getConnection } from "./data/connection";
import { ConnectionSyncStatus, Prisma, OrgRole, RepoIndexingStatus, StripeSubscriptionStatus } from "@sourcebot/db";
import { headers } from "next/headers"
import { cookies, headers } from "next/headers"
import { getStripe } from "@/lib/stripe"
import { getUser } from "@/data/user";
import { Session } from "next-auth";
@ -26,6 +26,7 @@ import InviteUserEmail from "./emails/inviteUserEmail";
import { createTransport } from "nodemailer";
import { repositoryQuerySchema } from "./lib/schemas";
import { RepositoryQuery } from "./lib/types";
import { MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME } from "./lib/constants";
const ajv = new Ajv({
validateFormats: false,
@ -1231,6 +1232,10 @@ export const getOrgInvites = async (domain: string) =>
})
);
export const dismissMobileUnsupportedSplashScreen = async () => {
await cookies().set(MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME, 'true');
}
////// Helpers ///////

View file

@ -0,0 +1,42 @@
'use client';
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { TriangleAlert } from "lucide-react";
import { useCallback, useEffect } from "react";
import { dismissMobileUnsupportedSplashScreen } from "@/actions";
import useCaptureEvent from "@/hooks/useCaptureEvent";
export const MobileUnsupportedSplashScreen = () => {
const captureEvent = useCaptureEvent();
useEffect(() => {
captureEvent('wa_mobile_unsupported_splash_screen_displayed', {});
}, [captureEvent]);
const onDismissed = useCallback(() => {
dismissMobileUnsupportedSplashScreen();
captureEvent('wa_mobile_unsupported_splash_screen_dismissed', {});
}, [captureEvent]);
return (
<div className="flex flex-col items-center justify-center p-2 min-h-screen bg-backgroundSecondary">
<Card className="flex flex-col items-center text-center mb-10 p-4 max-w-sm">
<TriangleAlert className="w-10 h-10 mb-4 text-yellow-600/90 dark:text-yellow-300/90" />
<div className="text-2xl font-semibold flex items-center mb-2">
Mobile is not supported.
</div>
<p className="text-sm text-muted-foreground mb-8">
Sourcebot on mobile is still a work in progress. Please use a desktop computer to get the best experience.
</p>
<Button
className="w-full"
variant="outline"
onClick={onDismissed}
>
Continue anyway
</Button>
</Card>
</div>
)
}

View file

@ -6,6 +6,10 @@ import { isServiceError } from "@/lib/utils";
import { OnboardGuard } from "./components/onboardGuard";
import { fetchSubscription } from "@/actions";
import { UpgradeGuard } from "./components/upgradeGuard";
import { cookies, headers } from "next/headers";
import { getSelectorsByUserAgent } from "react-device-detect";
import { MobileUnsupportedSplashScreen } from "./components/mobileUnsupportedSplashScreen";
import { MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME } from "@/lib/constants";
interface LayoutProps {
children: React.ReactNode,
@ -65,5 +69,15 @@ export default async function Layout({
)
}
const headersList = await headers();
const cookieStore = await cookies()
const userAgent = headersList.get('user-agent');
const { isMobile } = getSelectorsByUserAgent(userAgent ?? '');
if (isMobile && !cookieStore.has(MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME)) {
return (
<MobileUnsupportedSplashScreen />
)
}
return children;
}

View file

@ -24,15 +24,15 @@ export default async function Upgrade({ params: { domain } }: { params: { domain
const isTrialing = !isServiceError(subscription) ? subscription.status === "trialing" : false;
return (
<div className="flex flex-col items-center pt-12 min-h-screen bg-backgroundSecondary relative">
<div className="flex flex-col items-center pt-12 px-4 sm:px-12 min-h-screen bg-backgroundSecondary relative">
{isTrialing && (
<Link href={`/${domain}`} className="text-sm text-muted-foreground mb-5 absolute top-0 left-0 p-12">
<Link href={`/${domain}`} className="text-sm text-muted-foreground mb-5 absolute top-0 left-0 p-4 sm:p-12">
<div className="flex flex-row items-center gap-2">
<ArrowLeftIcon className="w-4 h-4" /> Return to dashboard
</div>
</Link>
)}
<LogoutEscapeHatch className="absolute top-0 right-0 p-12" />
<LogoutEscapeHatch className="absolute top-0 right-0 p-4 sm:p-12" />
<div className="flex flex-col items-center">
<SourcebotLogo
className="h-16 mb-2"

View file

@ -21,4 +21,6 @@ export const TEAM_FEATURES = [
"Public and private repos supported.",
"Create shareable links to code snippets.",
"Powerful regex and symbol search",
]
]
export const MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME = 'sb.mobile-unsupported-splash-screen-dismissed';

View file

@ -219,6 +219,8 @@ export type PosthogEventMap = {
wa_login_with_magic_link: {},
wa_login_with_credentials: {},
//////////////////////////////////////////////////////////////////
wa_mobile_unsupported_splash_screen_dismissed: {},
wa_mobile_unsupported_splash_screen_displayed: {},
}
export type PosthogEvent = keyof PosthogEventMap;

View file

@ -7716,6 +7716,13 @@ raw-body@2.5.2:
iconv-lite "0.4.24"
unpipe "1.0.0"
react-device-detect@^2.2.3:
version "2.2.3"
resolved "https://registry.npmjs.org/react-device-detect/-/react-device-detect-2.2.3.tgz#97a7ae767cdd004e7c3578260f48cf70c036e7ca"
integrity sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==
dependencies:
ua-parser-js "^1.0.33"
react-dom@^18:
version "18.3.1"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz"
@ -8616,14 +8623,7 @@ stringify-entities@^4.0.0:
character-entities-html4 "^2.0.0"
character-entities-legacy "^3.0.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@ -9030,6 +9030,11 @@ typescript@^5.7.3:
resolved "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz"
integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==
ua-parser-js@^1.0.33:
version "1.0.40"
resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz#ac6aff4fd8ea3e794a6aa743ec9c2fc29e75b675"
integrity sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==
uc.micro@^2.0.0, uc.micro@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz"