mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2026-03-23 10:45:21 +00:00
feat(app): auto-start geolocation after login (#756)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9a6ec7d7c4
commit
606b0fb649
@ -207,6 +207,7 @@ function App() {
|
||||
embedded={embedded}
|
||||
openCollectiveApiKey={config.openCollectiveApiKey}
|
||||
hideSignup={map.hide_signup}
|
||||
autoLocateOnLogin={map.auto_locate_on_login}
|
||||
>
|
||||
<Permissions api={permissionsApiInstance} adminRole={config.adminRole} />
|
||||
{tagsApi && <Tags api={tagsApi}></Tags>}
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
{
|
||||
"collection": "maps",
|
||||
"field": "auto_locate_on_login",
|
||||
"type": "boolean",
|
||||
"meta": {
|
||||
"collection": "maps",
|
||||
"conditions": null,
|
||||
"display": null,
|
||||
"display_options": null,
|
||||
"field": "auto_locate_on_login",
|
||||
"group": "Presets",
|
||||
"hidden": false,
|
||||
"interface": "boolean",
|
||||
"note": "Automatically start geolocation after user login",
|
||||
"options": null,
|
||||
"readonly": false,
|
||||
"required": false,
|
||||
"sort": 3,
|
||||
"special": [
|
||||
"cast-boolean"
|
||||
],
|
||||
"translations": null,
|
||||
"validation": null,
|
||||
"validation_message": null,
|
||||
"width": "half"
|
||||
},
|
||||
"schema": {
|
||||
"name": "auto_locate_on_login",
|
||||
"table": "maps",
|
||||
"data_type": "boolean",
|
||||
"default_value": false,
|
||||
"max_length": null,
|
||||
"numeric_precision": null,
|
||||
"numeric_scale": null,
|
||||
"is_nullable": true,
|
||||
"is_unique": false,
|
||||
"is_indexed": false,
|
||||
"is_primary_key": false,
|
||||
"is_generated": false,
|
||||
"generation_expression": null,
|
||||
"has_auto_increment": false,
|
||||
"foreign_key_table": null,
|
||||
"foreign_key_column": null
|
||||
}
|
||||
}
|
||||
@ -16,6 +16,7 @@ export function AppShell({
|
||||
embedded,
|
||||
openCollectiveApiKey,
|
||||
hideSignup,
|
||||
autoLocateOnLogin,
|
||||
}: {
|
||||
appName: string
|
||||
children: React.ReactNode
|
||||
@ -23,6 +24,7 @@ export function AppShell({
|
||||
embedded?: boolean
|
||||
openCollectiveApiKey?: string
|
||||
hideSignup?: boolean
|
||||
autoLocateOnLogin?: boolean
|
||||
}) {
|
||||
return (
|
||||
<ContextWrapper>
|
||||
@ -32,6 +34,7 @@ export function AppShell({
|
||||
embedded={embedded}
|
||||
openCollectiveApiKey={openCollectiveApiKey}
|
||||
hideSignup={hideSignup}
|
||||
autoLocateOnLogin={autoLocateOnLogin}
|
||||
/>
|
||||
<NavBar appName={appName}></NavBar>
|
||||
<div id='app-content' className='tw:flex'>
|
||||
|
||||
@ -9,11 +9,13 @@ export const SetAppState = ({
|
||||
embedded,
|
||||
openCollectiveApiKey,
|
||||
hideSignup,
|
||||
autoLocateOnLogin,
|
||||
}: {
|
||||
assetsApi: AssetsApi
|
||||
embedded?: boolean
|
||||
openCollectiveApiKey?: string
|
||||
hideSignup?: boolean
|
||||
autoLocateOnLogin?: boolean
|
||||
}) => {
|
||||
const setAppState = useSetAppState()
|
||||
|
||||
@ -33,5 +35,9 @@ export const SetAppState = ({
|
||||
setAppState({ hideSignup: hideSignup ?? false })
|
||||
}, [hideSignup, setAppState])
|
||||
|
||||
useEffect(() => {
|
||||
setAppState({ autoLocateOnLogin: autoLocateOnLogin ?? false })
|
||||
}, [autoLocateOnLogin, setAppState])
|
||||
|
||||
return <></>
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ interface AppState {
|
||||
embedded: boolean
|
||||
openCollectiveApiKey: string
|
||||
hideSignup: boolean
|
||||
autoLocateOnLogin: boolean
|
||||
}
|
||||
|
||||
type UseAppManagerResult = ReturnType<typeof useAppManager>
|
||||
@ -23,6 +24,7 @@ const initialAppState: AppState = {
|
||||
embedded: false,
|
||||
openCollectiveApiKey: '',
|
||||
hideSignup: false,
|
||||
autoLocateOnLogin: false,
|
||||
}
|
||||
|
||||
const AppContext = createContext<UseAppManagerResult>({
|
||||
|
||||
@ -8,6 +8,7 @@ import { useNavigate } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import TargetSVG from '#assets/target.svg'
|
||||
import { useAppState } from '#components/AppShell/hooks/useAppState'
|
||||
import { useAuth } from '#components/Auth/useAuth'
|
||||
import { useAddItem, useUpdateItem } from '#components/Map/hooks/useItems'
|
||||
import { useLayers } from '#components/Map/hooks/useLayers'
|
||||
@ -39,11 +40,16 @@ export const LocateControl = (): React.JSX.Element => {
|
||||
const updateItem = useUpdateItem()
|
||||
const addItem = useAddItem()
|
||||
const layers = useLayers()
|
||||
const { user } = useAuth()
|
||||
const { user, isInitialized } = useAuth()
|
||||
const { autoLocateOnLogin } = useAppState()
|
||||
const navigate = useNavigate()
|
||||
|
||||
// Prevent React 18 StrictMode from calling useEffect twice
|
||||
const init = useRef(false)
|
||||
// Track whether auto-locate has already fired (one-shot per session)
|
||||
const hasAutoLocatedRef = useRef(false)
|
||||
// Snapshot of user after initial auth completes — changes after this are real logins
|
||||
const initialUserRef = useRef<typeof user>(undefined)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
|
||||
const [lc, setLc] = useState<any>(null)
|
||||
@ -89,6 +95,28 @@ export const LocateControl = (): React.JSX.Element => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
// Auto-start location tracking after a real login (not page reload)
|
||||
useEffect(() => {
|
||||
if (!isInitialized || !autoLocateOnLogin || !lc) return
|
||||
|
||||
// First time isInitialized is true: snapshot the current user as baseline
|
||||
if (initialUserRef.current === undefined) {
|
||||
initialUserRef.current = user
|
||||
return
|
||||
}
|
||||
|
||||
// If user changed from null to a value after the baseline was set, it's a real login
|
||||
if (!hasAutoLocatedRef.current && user && initialUserRef.current === null) {
|
||||
hasAutoLocatedRef.current = true
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
||||
lc.start()
|
||||
setLoading(true)
|
||||
setHasDeclinedModal(false)
|
||||
}
|
||||
|
||||
initialUserRef.current = user
|
||||
}, [isInitialized, user, lc, autoLocateOnLogin])
|
||||
|
||||
// Check if user logged in while location is active and found
|
||||
useEffect(() => {
|
||||
if (
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user