Skip to content

Commit

Permalink
Auth Flow added
Browse files Browse the repository at this point in the history
with auth store & api
  • Loading branch information
kanzitelli committed Mar 15, 2023
1 parent 05e14bd commit ae34b1d
Show file tree
Hide file tree
Showing 10 changed files with 311 additions and 75 deletions.
30 changes: 22 additions & 8 deletions src/navio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import {Navio} from 'rn-navio';

import {Main} from '@app/screens/main';
import {Playground} from '@app/screens/playground';
import {PlaygroundFlashList} from '@app/screens/playground/flash-list';
import {PlaygroundExpoImage} from '@app/screens/playground/expo-image';
import {Settings} from '@app/screens/settings';
import {Example} from '@app/screens/_screen-sample';

Expand All @@ -13,25 +15,29 @@ import {
drawerScreenDefaultOptions,
} from '@app/utils/designSystem';
import {services} from '@app/services';
import {AuthLogin} from './screens/auth/login';

// NAVIO
export const navio = Navio.build({
screens: {
Main,
Settings,
Example,
Playground: {
component: Playground,
options: () => ({
title: 'Playground',
}),
},

Playground,
PlaygroundFlashList,
PlaygroundExpoImage,

// for .pushStack example
ProductPage: {
component: Example,
options: {
headerShown: false,
},
},

// for auth flow
AuthLogin,
},
stacks: {
MainStack: ['Main', 'Example'],
Expand All @@ -43,13 +49,21 @@ export const navio = Navio.build({
},
},
},
PlaygroundStack: {
screens: ['Playground', 'PlaygroundFlashList', 'PlaygroundExpoImage'],
},

// for .pushStack example
ProductPageStack: {
screens: ['ProductPage'],
containerOptions: {
headerShown: true,
title: 'Product page',
},
},

// for auth flow
AuthFlow: ['AuthLogin', 'Example'],
},
tabs: {
AppTabs: {
Expand All @@ -62,7 +76,7 @@ export const navio = Navio.build({
}),
},
PlaygroundTab: {
stack: ['Playground'],
stack: 'PlaygroundStack',
options: () => ({
title: 'Playground',
tabBarIcon: getTabBarIcon('PlaygroundTab'),
Expand Down Expand Up @@ -92,7 +106,7 @@ export const navio = Navio.build({
},
},
Example: 'ExampleStack',
Playground: ['Playground'],
Playground: 'PlaygroundStack',
},
},
},
Expand Down
109 changes: 109 additions & 0 deletions src/screens/auth/login.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import React, {useEffect, useState} from 'react';
import {ScrollView} from 'react-native';
import {TextInput} from 'react-native-gesture-handler';
import {View, Text, Colors} from 'react-native-ui-lib';
import {observer} from 'mobx-react';
import {NavioScreen} from 'rn-navio';

import {useStores} from '@app/stores';
import {useServices} from '@app/services';
import {useAppearance} from '@app/utils/hooks';
import {BButton} from '@app/components/button';

export type Props = {
type?: 'push';
};

export const AuthLogin: NavioScreen<Props> = observer(({type = 'push'}) => {
useAppearance(); // for Dark Mode
const {t, navio, api} = useServices();
const {auth} = useStores();

// State
const [loading, setLoading] = useState(false);
const [password, setPassword] = useState('');

// Start
useEffect(() => {
configureUI();
}, []);

// API Methods
const login = async () => {
setLoading(true);

try {
const {status} = await api.auth.login(); // fake login

if (status === 'success') {
// marking that we are logged in
auth.set('state', 'logged-in');

// navigating to main app
navio.setRoot('tabs', 'AppTabs');
}
} catch (e) {
// handle error
} finally {
setLoading(false);
}
};

// Methods
const configureUI = () => {};

const setEmail = (v: string) => auth.set('email', v);

return (
<View flex bg-bgColor>
<ScrollView contentInsetAdjustmentBehavior="always">
<View>
<View flex centerH marginT-30>
<Text text50>Login</Text>

<Text grey30 marginT-4>
just fill in any credentials
</Text>
</View>

<View marginT-s6 centerH>
<View
paddingH-s4
marginV-s10
style={{width: 300, borderWidth: 1, borderColor: Colors.grey50, borderRadius: 12}}
>
<View paddingH-s3 paddingV-s2 marginV-s4>
<TextInput
placeholder={'Email'}
value={auth.email}
onChangeText={setEmail}
keyboardType="email-address"
inputMode="email"
/>
</View>

<View centerH>
<View height={1} bg-grey50 style={{width: '100%'}} />
</View>

<View paddingH-s3 paddingV-s2 marginV-s4>
<TextInput
placeholder={'Password'}
value={password}
onChangeText={setPassword}
keyboardType="visible-password"
secureTextEntry
/>
</View>
</View>

<BButton label={loading ? 'Logging in ...' : 'Login'} onPress={login} />
</View>
</View>
</ScrollView>
</View>
);
});
AuthLogin.options = props => ({
title: `Auth flow`,
});
161 changes: 100 additions & 61 deletions src/screens/playground/index.tsx
Original file line number Diff line number Diff line change
@@ -1,81 +1,120 @@
import React, {useMemo} from 'react';
import {Image} from 'expo-image';
import {Text, View} from 'react-native-ui-lib';
import {FlashList} from '@shopify/flash-list';
import {observer} from 'mobx-react';
import {ScrollView} from 'react-native-gesture-handler';
import {Bounceable} from 'rn-bounceable';
import {If} from '@kanzitelli/if-component';

import {useStores} from '@app/stores';
import {useServices} from '@app/services';
import {useAppearance} from '@app/utils/hooks';
import {randomStr} from '@app/utils/help';
import {Row} from '@app/components/row';
import {Icon} from '@app/components/icon';
import {Section} from '@app/components/section';

const blurhash =
'|rF?hV%2WCj[ayj[a|j[az_NaeWBj@ayfRayfQfQM{M|azj[azf6fQfQfQIpWXofj[ayj[j[fQayWCoeoeaya}j[ayfQa{oLj?j[WVj[ayayj[fQoff7azayj[ayj[j[ayofayayayj[fQj[ayayj[ayfjj[j[ayjuayj[';
type SectionData = {
content: {
title: string;
subtitle?: string;
icon: string;
onPress: PureFunc;
}[];
};

export const Playground: React.FC = observer(() => {
useAppearance();
// const {t} = useServices();
// const {ui} = useStores();

const DATA = useMemo(
() =>
Array.from({length: 1000}).map((v, ndx) => ({
title: `Item ${ndx}`,
image: `https://picsum.photos/200?image=${ndx + 1}`,
description: randomStr(300),
})),
[],
);

// State
const {navio} = useServices();
const {auth} = useStores();

// Methods
// UI Methods
const showAuthFlow = () => {
// logging out from previous session
if (auth.state === 'logged-in') {
auth.logout();
} else {
// we can move `navio.setRoot` inside `auth.logout`
// but is left here for more clarity and simplicity
navio.setRoot('stacks', 'AuthFlow');
}
};

return (
<View flex bg-bgColor>
<FlashList
contentInsetAdjustmentBehavior="always"
data={DATA}
renderItem={({item}) => <ListItem item={item} />}
ListHeaderComponent={ListHeader}
estimatedItemSize={300}
/>
</View>
);
});
// Memos
const SectionsData: Record<string, SectionData> = useMemo(() => {
return {
Libraries: {
content: [
{
title: 'Flash List',
subtitle: 'by Shopify',
icon: 'list-outline',
onPress: () => navio.push('PlaygroundFlashList'),
},
{
title: 'Expo Image',
subtitle: 'by Expo',
icon: 'image-outline',
onPress: () => navio.push('PlaygroundExpoImage'),
},
],
},
Navio: {
content: [
{
title: 'Auth flow',
icon: 'lock-closed-outline',
subtitle: auth.stateStr,
onPress: showAuthFlow,
},
],
},
};
}, [auth.state]);

const ListItem = ({item}: any) => {
useAppearance();

return (
<View padding-s2 bg-bgColor>
<Image
style={{width: 120, height: 120, borderRadius: 20}}
source={item.image}
placeholder={blurhash}
contentFit="cover"
resizeMode="contain"
transition={100}
/>
// UI Methods
const Sections = useMemo(() => {
const keys = Object.keys(SectionsData) as (keyof typeof SectionsData)[];
return keys.map(k => {
const s = SectionsData[k];
return (
<Section key={k} title={k}>
{s.content.map(content => {
return (
<View key={content.title} marginV-s1>
<Bounceable onPress={content.onPress}>
<View bg-bg2Color padding-s3 br30>
<Row>
<Icon name={content.icon} size={34} />

<Text textColor text50R>
{item.title}
</Text>
<View flex marginH-s3>
<Text text60R textColor>
{content.title}
</Text>

<Text textColor text70R>
{item.description}
</Text>
</View>
);
};
{If({
_: !!content.subtitle,
_then: (
<Text text70 grey20>
{content.subtitle}
</Text>
),
})}
</View>

const ListHeader = () => {
useAppearance();
<Icon name="chevron-forward" />
</Row>
</View>
</Bounceable>
</View>
);
})}
</Section>
);
});
}, [SectionsData]);

return (
<View padding-s2 bg-bgColor>
<Text text50M textColor>
FlashList by Shopify
</Text>
<View flex bg-bgColor>
<ScrollView contentInsetAdjustmentBehavior="always">{Sections}</ScrollView>
</View>
);
};
});
16 changes: 16 additions & 0 deletions src/services/api/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {sleep} from '@app/utils/help';
import {Auth$Login$Response} from '@app/utils/types/api';

export class AuthApi {
login = async (): Promise<Auth$Login$Response> => {
// faking request
await sleep(1000); // sleeping for 1s

return {
status: 'success',
data: {
'some-session-info?': {},
},
};
};
}

0 comments on commit ae34b1d

Please sign in to comment.