From eb92029cb0db66e143f9e9887bfb67c317752f8a Mon Sep 17 00:00:00 2001
From: Adam Xu
Date: Thu, 26 Feb 2026 10:23:33 -0800
Subject: [PATCH 1/2] add mobile onboarding route and bridge integration
---
src/app/mobile/onboarding/page.tsx | 7 ++
src/app/onboarding/page.tsx | 2 +-
src/components/LayoutWrapper.tsx | 11 ++-
src/components/onboarding/ConnectLmsStep.tsx | 21 ++++-
.../onboarding/OnboardingController.tsx | 53 ++++++++++--
src/lib/mobileBridge.ts | 80 +++++++++++++++++++
src/types/mobileBridge.d.ts | 16 ++++
7 files changed, 178 insertions(+), 12 deletions(-)
create mode 100644 src/app/mobile/onboarding/page.tsx
create mode 100644 src/lib/mobileBridge.ts
create mode 100644 src/types/mobileBridge.d.ts
diff --git a/src/app/mobile/onboarding/page.tsx b/src/app/mobile/onboarding/page.tsx
new file mode 100644
index 0000000..408df0b
--- /dev/null
+++ b/src/app/mobile/onboarding/page.tsx
@@ -0,0 +1,7 @@
+'use client';
+
+import { OnboardingController } from '@/components/onboarding/OnboardingController';
+
+export default function MobileOnboardingPage() {
+ return ;
+}
diff --git a/src/app/onboarding/page.tsx b/src/app/onboarding/page.tsx
index ac35f64..8a861ef 100644
--- a/src/app/onboarding/page.tsx
+++ b/src/app/onboarding/page.tsx
@@ -3,5 +3,5 @@
import { OnboardingController } from '@/components/onboarding/OnboardingController';
export default function OnboardingPage() {
- return ;
+ return ;
}
diff --git a/src/components/LayoutWrapper.tsx b/src/components/LayoutWrapper.tsx
index bc3210d..17db1d7 100644
--- a/src/components/LayoutWrapper.tsx
+++ b/src/components/LayoutWrapper.tsx
@@ -13,10 +13,12 @@ type AuthState = {
export function LayoutWrapper({ children }: { children: React.ReactNode }) {
const pathname = usePathname();
const [authState, setAuthState] = useState(null);
+ const isHelpRoute = pathname.startsWith('/help');
+ const isMobileOnboardingRoute = pathname.startsWith('/mobile/onboarding');
useEffect(() => {
// Skip auth check for help/docs routes
- if (pathname.startsWith('/help')) {
+ if (isHelpRoute) {
return;
}
@@ -40,10 +42,10 @@ export function LayoutWrapper({ children }: { children: React.ReactNode }) {
};
checkAuth();
- }, [pathname]);
+ }, [isHelpRoute, pathname]);
// Bypass auth check for help/docs routes
- if (pathname.startsWith('/help')) {
+ if (isHelpRoute) {
return <>{children}>;
}
@@ -54,6 +56,9 @@ export function LayoutWrapper({ children }: { children: React.ReactNode }) {
// If authenticated
if (authState.isAuthenticated) {
+ if (isMobileOnboardingRoute) {
+ return <>{children}>;
+ }
// Check if onboarding is incomplete
if (authState.onboardingStep && authState.onboardingStep !== 'completed') {
return ;
diff --git a/src/components/onboarding/ConnectLmsStep.tsx b/src/components/onboarding/ConnectLmsStep.tsx
index 2b16bde..4947c57 100644
--- a/src/components/onboarding/ConnectLmsStep.tsx
+++ b/src/components/onboarding/ConnectLmsStep.tsx
@@ -3,10 +3,17 @@
import { useEffect, useRef, useState } from 'react';
import { useSearchParams } from 'next/navigation';
import { OnboardingSlide } from './OnboardingSlide';
+import { mobileBridge } from '@/lib/mobileBridge';
const BACKGROUND_COLOR = '#2563eb';
-export function ConnectLmsStep() {
+type OnboardingMode = 'web' | 'mobile';
+
+interface ConnectLmsStepProps {
+ mode?: OnboardingMode;
+}
+
+export function ConnectLmsStep({ mode = 'web' }: ConnectLmsStepProps) {
const searchParams = useSearchParams();
const error = searchParams.get('error');
const [overrideOpen, setOverrideOpen] = useState(false);
@@ -22,7 +29,13 @@ export function ConnectLmsStep() {
};
}, []);
- const handleConnect = () => {
+ const handleConnect = async () => {
+ if (mode === 'mobile') {
+ const bridged = await mobileBridge.startSchoologyOAuth();
+ if (bridged) {
+ return;
+ }
+ }
window.location.href = `${process.env.NEXT_PUBLIC_BACKEND_URL}/oauth/schoology/start`;
};
@@ -87,7 +100,9 @@ export function ConnectLmsStep() {
)}