This commit is contained in:
2026-03-31 10:23:49 +05:30
parent f488400c6d
commit cfecfa5116
8 changed files with 21 additions and 23 deletions

View File

@@ -38,6 +38,7 @@ class UserUpdate(BaseModel):
displayName: Optional[str] = None
photoURL: Optional[str] = None
theme: Optional[str] = None
tutorial: Optional[bool] = None
class Config:
json_schema_extra = {
@@ -56,6 +57,7 @@ class User(BaseModel):
createdAt: datetime
updatedAt: datetime
theme: str = "light"
tutorial: Optional[bool] = None
class Config:
from_attributes = True

View File

@@ -79,6 +79,7 @@ async def get_user_by_email(email: str):
"displayName": user.get("displayName"),
"photoURL": user.get("photoURL"),
"theme": user.get("theme", "light"),
"tutorial": user.get("tutorial"),
"createdAt": user["createdAt"].isoformat(),
"updatedAt": user["updatedAt"].isoformat()
}
@@ -151,6 +152,7 @@ async def update_user(user_id: str, user_data: UserUpdate):
"displayName": user.get("displayName"),
"photoURL": user.get("photoURL"),
"theme": user.get("theme", "light"),
"tutorial": user.get("tutorial"),
"createdAt": user["createdAt"].isoformat(),
"updatedAt": user["updatedAt"].isoformat(),
"message": "User updated successfully"

View File

@@ -37,6 +37,7 @@ type MongoUser = {
displayName?: string
photoURL?: string
theme?: string
tutorial?: boolean
}
type AuthContextValue = {
@@ -211,8 +212,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
// Clear secret key from memory
setSecretKey(null)
setMongoUser(null)
// Reset onboarding so tour shows again on next login
localStorage.removeItem('gj-onboarding-done')
// Clear pending tour step (session state)
localStorage.removeItem('gj-tour-pending-step')
// Keep device key and encrypted key for next login
// Do NOT clear localStorage or IndexedDB

View File

@@ -3,17 +3,8 @@ import { useNavigate } from 'react-router-dom'
import { driver, type DriveStep } from 'driver.js'
import 'driver.js/dist/driver.css'
const ONBOARDING_KEY = 'gj-onboarding-done'
const TOUR_PENDING_KEY = 'gj-tour-pending-step'
export function hasSeenOnboarding(): boolean {
return localStorage.getItem(ONBOARDING_KEY) === 'true'
}
export function markOnboardingDone(): void {
localStorage.setItem(ONBOARDING_KEY, 'true')
}
export function hasPendingTourStep(): string | null {
return localStorage.getItem(TOUR_PENDING_KEY)
}
@@ -144,7 +135,6 @@ export function useOnboardingTour() {
const driverObj = driver({
...driverDefaults(),
onDestroyStarted: () => {
markOnboardingDone()
clearPendingTourStep()
driverObj.destroy()
},
@@ -175,7 +165,6 @@ export function useOnboardingTour() {
const driverObj = driver({
...driverDefaults(),
onDestroyStarted: () => {
markOnboardingDone()
clearPendingTourStep()
driverObj.destroy()
},
@@ -206,7 +195,6 @@ export function useOnboardingTour() {
const driverObj = driver({
...driverDefaults(),
onDestroyStarted: () => {
markOnboardingDone()
clearPendingTourStep()
driverObj.destroy()
},
@@ -216,7 +204,6 @@ export function useOnboardingTour() {
// Last settings step → navigate to /
if (activeIndex === steps.length - 1) {
markOnboardingDone()
clearPendingTourStep()
driverObj.destroy()
navigate('/')

View File

@@ -70,7 +70,7 @@ export async function getUserByEmail(email: string, token: string) {
export async function updateUserProfile(
userId: string,
updates: { displayName?: string; photoURL?: string; theme?: string },
updates: { displayName?: string; photoURL?: string; theme?: string; tutorial?: boolean },
token: string
) {
return apiCall(`/users/${userId}`, {

View File

@@ -1,12 +1,12 @@
import { useAuth } from '../contexts/AuthContext'
import { Link, useNavigate } from 'react-router-dom'
import { useState, useRef, useEffect } from 'react'
import { createEntry } from '../lib/api'
import { createEntry, updateUserProfile } from '../lib/api'
import { encryptEntry } from '../lib/crypto'
import BottomNav from '../components/BottomNav'
import WelcomeModal from '../components/WelcomeModal'
import { SaveBookAnimation } from '../components/SaveBookAnimation'
import { useOnboardingTour, hasSeenOnboarding, markOnboardingDone } from '../hooks/useOnboardingTour'
import { useOnboardingTour } from '../hooks/useOnboardingTour'
import { PageLoader } from '../components/PageLoader'
const AFFIRMATIONS = [
@@ -31,7 +31,7 @@ const SAVE_LEAVES = [
]
export default function HomePage() {
const { user, userId, secretKey, loading } = useAuth()
const { user, userId, mongoUser, secretKey, loading } = useAuth()
const navigate = useNavigate()
const [entry, setEntry] = useState('')
const [title, setTitle] = useState('')
@@ -47,19 +47,26 @@ export default function HomePage() {
// Check if onboarding should be shown after login
useEffect(() => {
if (!loading && user && userId && !hasSeenOnboarding()) {
if (!loading && user && userId && mongoUser && !mongoUser.tutorial) {
setShowWelcome(true)
}
}, [loading, user, userId])
}, [loading, user, userId, mongoUser])
async function markTutorialDone() {
if (!user || !userId) return
const token = await user.getIdToken()
updateUserProfile(userId, { tutorial: true }, token).catch(console.error)
}
const handleStartTour = () => {
setShowWelcome(false)
markTutorialDone()
startTour()
}
const handleSkipTour = () => {
setShowWelcome(false)
markOnboardingDone()
markTutorialDone()
}
if (loading) {

View File

@@ -28,7 +28,7 @@ export default function LoginPage() {
}
}
if (loading) {
if (loading || signingIn) {
return <PageLoader />
}