Get MVP of web app running
parent
751dfb20fd
commit
a3d2db9645
|
@ -1,7 +1,8 @@
|
|||
import React, {useState, useEffect} from 'react'
|
||||
import {SafeAreaProvider} from 'react-native-safe-area-context'
|
||||
import * as view from './view/index'
|
||||
import {RootStoreModel, setupState, RootStoreProvider} from './state'
|
||||
import {DesktopWebShell} from './view/shell/desktop-web'
|
||||
import {WebShell} from './view/shell/web'
|
||||
// import Toast from 'react-native-root-toast' TODO
|
||||
|
||||
function App() {
|
||||
|
@ -22,7 +23,9 @@ function App() {
|
|||
|
||||
return (
|
||||
<RootStoreProvider value={rootStore}>
|
||||
<DesktopWebShell />
|
||||
<SafeAreaProvider>
|
||||
<WebShell />
|
||||
</SafeAreaProvider>
|
||||
</RootStoreProvider>
|
||||
)
|
||||
// <Toast.ToastContainer /> TODO
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
} from '@fortawesome/react-native-fontawesome'
|
||||
import {ComAtprotoAccountCreate} from '@atproto/api'
|
||||
import * as EmailValidator from 'email-validator'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
// import {useAnalytics} from '@segment/analytics-react-native' TODO
|
||||
import {LogoTextHero} from './Logo'
|
||||
import {Picker} from '../util/Picker'
|
||||
import {TextLink} from '../util/Link'
|
||||
|
@ -32,7 +32,7 @@ import {ServerInputModal} from '../../../state/models/shell-ui'
|
|||
import {usePalette} from '../../lib/hooks/usePalette'
|
||||
|
||||
export const CreateAccount = ({onPressBack}: {onPressBack: () => void}) => {
|
||||
const {track} = useAnalytics()
|
||||
// const {track} = useAnalytics() TODO
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const [isProcessing, setIsProcessing] = useState<boolean>(false)
|
||||
|
@ -109,7 +109,7 @@ export const CreateAccount = ({onPressBack}: {onPressBack: () => void}) => {
|
|||
password,
|
||||
inviteCode,
|
||||
})
|
||||
track('Create Account')
|
||||
// track('Create Account') TODO
|
||||
} catch (e: any) {
|
||||
let errMsg = e.toString()
|
||||
if (e instanceof ComAtprotoAccountCreate.InvalidInviteCodeError) {
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
} from '@fortawesome/react-native-fontawesome'
|
||||
import * as EmailValidator from 'email-validator'
|
||||
import {sessionClient as AtpApi, SessionServiceClient} from '@atproto/api'
|
||||
import {useAnalytics} from '@segment/analytics-react-native'
|
||||
// import {useAnalytics} from '@segment/analytics-react-native' TODO
|
||||
import {LogoTextHero} from './Logo'
|
||||
import {Text} from '../util/text/Text'
|
||||
import {UserAvatar} from '../util/UserAvatar'
|
||||
|
@ -153,7 +153,7 @@ const ChooseAccountForm = ({
|
|||
onSelectAccount: (account?: AccountData) => void
|
||||
onPressBack: () => void
|
||||
}) => {
|
||||
const {track} = useAnalytics()
|
||||
// const {track} = useAnalytics() TODO
|
||||
const pal = usePalette('default')
|
||||
const [isProcessing, setIsProcessing] = React.useState(false)
|
||||
|
||||
|
@ -161,7 +161,7 @@ const ChooseAccountForm = ({
|
|||
if (account.accessJwt && account.refreshJwt) {
|
||||
setIsProcessing(true)
|
||||
if (await store.session.resumeSession(account)) {
|
||||
track('Sign In', {resumedSession: true})
|
||||
// track('Sign In', {resumedSession: true}) TODO
|
||||
setIsProcessing(false)
|
||||
return
|
||||
}
|
||||
|
@ -261,7 +261,7 @@ const LoginForm = ({
|
|||
onPressBack: () => void
|
||||
onPressForgotPassword: () => void
|
||||
}) => {
|
||||
const {track} = useAnalytics()
|
||||
// const {track} = useAnalytics() TODO
|
||||
const pal = usePalette('default')
|
||||
const [isProcessing, setIsProcessing] = useState<boolean>(false)
|
||||
const [handle, setHandle] = useState<string>(initialHandle)
|
||||
|
@ -302,7 +302,7 @@ const LoginForm = ({
|
|||
handle: fullHandle,
|
||||
password,
|
||||
})
|
||||
track('Sign In', {resumedSession: false})
|
||||
// track('Sign In', {resumedSession: false}) TODO
|
||||
} catch (e: any) {
|
||||
const errMsg = e.toString()
|
||||
store.log.warn('Failed to login', e)
|
||||
|
|
|
@ -76,7 +76,11 @@ export function DropdownButton({
|
|||
onPress={onPress}
|
||||
hitSlop={HITSLOP}
|
||||
// Fix an issue where specific references cause runtime error in jest environment
|
||||
ref={process.env.JEST_WORKER_ID != null ? null : ref}>
|
||||
ref={
|
||||
typeof process !== 'undefined' && process.env.JEST_WORKER_ID != null
|
||||
? null
|
||||
: ref
|
||||
}>
|
||||
{children}
|
||||
</TouchableOpacity>
|
||||
)
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
import React from 'react'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {View, StyleSheet} from 'react-native'
|
||||
import {DesktopLeftColumn} from './left-column'
|
||||
import {DesktopRightColumn} from './right-column'
|
||||
import {useStores} from '../../../state'
|
||||
|
||||
export const DesktopWebShell: React.FC = observer(({children}) => {
|
||||
const store = useStores()
|
||||
return (
|
||||
<View style={styles.outerContainer}>
|
||||
{store.session.hasSession ? (
|
||||
<>
|
||||
<DesktopLeftColumn />
|
||||
<View style={styles.innerContainer}>{children}</View>
|
||||
<DesktopRightColumn />
|
||||
</>
|
||||
) : (
|
||||
<View style={styles.innerContainer}>{children}</View>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
outerContainer: {
|
||||
height: '100%',
|
||||
},
|
||||
innerContainer: {
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
width: '600px',
|
||||
height: '100%',
|
||||
},
|
||||
})
|
|
@ -0,0 +1,140 @@
|
|||
import React from 'react'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {View, StyleSheet, Text} from 'react-native'
|
||||
import {useStores} from '../../../state'
|
||||
import {match, MatchResult} from '../../routes'
|
||||
// import {DesktopLeftColumn} from './left-column'
|
||||
// import {DesktopRightColumn} from './right-column'
|
||||
import {Login} from '../../screens/Login'
|
||||
import {ErrorBoundary} from '../../com/util/ErrorBoundary'
|
||||
import {usePalette} from '../../lib/hooks/usePalette'
|
||||
import {s} from '../../lib/styles'
|
||||
|
||||
export const WebShell: React.FC = observer(() => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const screenRenderDesc = constructScreenRenderDesc(store.nav)
|
||||
|
||||
if (!store.session.hasSession) {
|
||||
return (
|
||||
<View style={styles.outerContainer}>
|
||||
<View style={styles.innerContainer}>
|
||||
<Login />
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[styles.outerContainer, pal.view]}>
|
||||
<View style={styles.innerContainer}>
|
||||
{screenRenderDesc.screens.map(({Com, navIdx, params, key, current}) => (
|
||||
<View
|
||||
key={key}
|
||||
style={[s.h100pct, current ? styles.visible : styles.hidden]}>
|
||||
<ErrorBoundary>
|
||||
<Com params={params} navIdx={navIdx} visible={current} />
|
||||
</ErrorBoundary>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
// TODO
|
||||
// <Modal />
|
||||
// <Lightbox />
|
||||
// <Composer
|
||||
// active={store.shell.isComposerActive}
|
||||
// onClose={() => store.shell.closeComposer()}
|
||||
// winHeight={winDim.height}
|
||||
// replyTo={store.shell.composerOpts?.replyTo}
|
||||
// imagesOpen={store.shell.composerOpts?.imagesOpen}
|
||||
// onPost={store.shell.composerOpts?.onPost}
|
||||
// />
|
||||
// return (
|
||||
// <View style={styles.outerContainer}>
|
||||
// {store.session.hasSession ? (
|
||||
// <>
|
||||
// <DesktopLeftColumn />
|
||||
// <View style={styles.innerContainer}>
|
||||
// <Text>Hello, world! (Logged in)</Text>
|
||||
// {children}
|
||||
// </View>
|
||||
// <DesktopRightColumn />
|
||||
// </>
|
||||
// ) : (
|
||||
// <View style={styles.innerContainer}>
|
||||
// <Text>Hello, world! (Logged out)</Text>
|
||||
// {children}
|
||||
// </View>
|
||||
// )}
|
||||
// </View>
|
||||
// )
|
||||
})
|
||||
|
||||
/**
|
||||
* This method produces the information needed by the shell to
|
||||
* render the current screens with screen-caching behaviors.
|
||||
*/
|
||||
type ScreenRenderDesc = MatchResult & {
|
||||
key: string
|
||||
navIdx: string
|
||||
current: boolean
|
||||
previous: boolean
|
||||
isNewTab: boolean
|
||||
}
|
||||
function constructScreenRenderDesc(nav: NavigationModel): {
|
||||
icon: IconProp
|
||||
hasNewTab: boolean
|
||||
screens: ScreenRenderDesc[]
|
||||
} {
|
||||
let hasNewTab = false
|
||||
let icon: IconProp = 'magnifying-glass'
|
||||
let screens: ScreenRenderDesc[] = []
|
||||
for (const tab of nav.tabs) {
|
||||
const tabScreens = [
|
||||
...tab.getBackList(5),
|
||||
Object.assign({}, tab.current, {index: tab.index}),
|
||||
]
|
||||
const parsedTabScreens = tabScreens.map(screen => {
|
||||
const isCurrent = nav.isCurrentScreen(tab.id, screen.index)
|
||||
const isPrevious = nav.isCurrentScreen(tab.id, screen.index + 1)
|
||||
const matchRes = match(screen.url)
|
||||
if (isCurrent) {
|
||||
icon = matchRes.icon
|
||||
}
|
||||
hasNewTab = hasNewTab || tab.isNewTab
|
||||
return Object.assign(matchRes, {
|
||||
key: `t${tab.id}-s${screen.index}`,
|
||||
navIdx: `${tab.id}-${screen.id}`,
|
||||
current: isCurrent,
|
||||
previous: isPrevious,
|
||||
isNewTab: tab.isNewTab,
|
||||
}) as ScreenRenderDesc
|
||||
})
|
||||
screens = screens.concat(parsedTabScreens)
|
||||
}
|
||||
return {
|
||||
icon,
|
||||
hasNewTab,
|
||||
screens,
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
outerContainer: {
|
||||
height: '100%',
|
||||
},
|
||||
innerContainer: {
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
width: '600px',
|
||||
height: '100%',
|
||||
},
|
||||
visible: {
|
||||
display: 'flex',
|
||||
},
|
||||
hidden: {
|
||||
display: 'none',
|
||||
},
|
||||
})
|
Loading…
Reference in New Issue