Skip to content

Commit 62a7be4

Browse files
committed
finish setting up login/signup ui
1 parent fd6e5b1 commit 62a7be4

File tree

13 files changed

+392
-189
lines changed

13 files changed

+392
-189
lines changed

client/package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717
"reset": "watchman watch-del-all; rm -rf /tmp/metro-bundler-cache-*; rm -rf ./android/build; rm -rf ./android/.gradle; rm -rf ./android/app/build; rm -rf ~/Library/Developer/Xcode/DerivedData; rm -rf /tmp/haste-map-react-native-packager-*; rm -rf ./ios/build; yarn install; pod install --project-directory=ios; react-native start --reset-cache"
1818
},
1919
"dependencies": {
20-
"@accounts/apollo-link": "^0.15.0",
21-
"@accounts/client": "^0.15.0",
22-
"@accounts/client-password": "^0.15.0",
23-
"@accounts/graphql-client": "^0.15.0",
20+
"@accounts/apollo-link": "^0.13.0",
21+
"@accounts/client": "^0.13.0",
22+
"@accounts/client-password": "^0.13.0",
23+
"@accounts/graphql-client": "^0.13.0",
2424
"apollo-boost": "^0.4.0",
25+
"formik": "^1.5.7",
2526
"graphql": "^14.3.1",
2627
"graphql-tools": "^4.0.4",
2728
"react": "16.8.6",

client/src/components/Button/Button.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ const Label = styled(Text)`
2020
interface ButtonProps {
2121
children: string
2222
onPress: () => void
23+
disabled?: boolean
2324
}
2425

25-
const Button = ({ children, onPress }: ButtonProps) => (
26-
<Wrapper onPress={onPress} activeOpacity={0.6}>
26+
const Button = ({ children, onPress, disabled }: ButtonProps) => (
27+
<Wrapper onPress={onPress} activeOpacity={0.6} disabled={disabled}>
2728
<Label>{children}</Label>
2829
</Wrapper>
2930
)

client/src/components/Input/Input.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as React from 'react'
22
import { View, Text, TextInput, TextInputIOSProps } from 'react-native'
33
import styled from 'styled-components'
44

5-
const Base = styled(TextInput)`
5+
const Base = styled(TextInput)<{ name?: string }>`
66
background: #ffffff;
77
padding: 12px 20px;
88
box-shadow: 0 13px 27px 0 rgba(0, 0, 0, 0.04);
@@ -23,28 +23,34 @@ const Label = styled(Text)`
2323

2424
interface InputProps {
2525
style?: any
26+
name?: string
2627
label?: string
2728
placeholder?: string
2829
value?: string
2930
onChangeText: (text: string) => void
31+
onBlur?: (e: any) => void
3032
secure?: boolean
3133
textContentType?: TextInputIOSProps['textContentType']
3234
}
3335

3436
const Input = ({
3537
style,
38+
name,
3639
label,
3740
placeholder,
3841
value,
3942
onChangeText,
43+
onBlur,
4044
secure,
4145
textContentType,
4246
}: InputProps) => (
4347
<View style={style}>
4448
{label && <Label>{label}</Label>}
4549
<Base
50+
name={name}
4651
value={value}
4752
onChangeText={onChangeText}
53+
onBlur={onBlur}
4854
placeholder={placeholder}
4955
placeholderTextColor="rgba(67, 91, 126, 0.3)"
5056
textContentType={textContentType}

client/src/components/Router/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ export default () => {
2828
<Switch>
2929
<Route path="/login" component={Login} />
3030
<Route path="/signup" component={Login} />
31+
<Route path="/landlord/login" component={Login} />
32+
<Route path="/landlord/signup" component={Login} />
3133
<Route path="*" render={() => <Redirect to="/login" />} />
3234
</Switch>
3335
)}

client/src/screens/Login/Login.tsx

Lines changed: 47 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,34 @@
11
import * as React from 'react'
2-
import { View, Image } from 'react-native'
2+
import { View, Text, Image } from 'react-native'
33
import styled from 'styled-components'
4+
import { Link } from '../../components/Router'
45
import logo from '../../assets/images/logo-full.svg'
5-
import Button from '../../components/Button'
6-
import Input from '../../components/Input'
76
import TabBox, { Tabs } from './components/TabBox'
87
import { useUserContext } from '../../screens/Login/UserContext'
8+
import LoginForm from './components/LoginForm'
9+
import SignupForm from './components/SignupForm'
10+
11+
const LinkToOtherLogin = (props: { isLandlord: boolean }) => (
12+
<View style={{ marginTop: 50 }}>
13+
{props.isLandlord ? (
14+
<Text style={{ color: '#EDEEF3' }}>
15+
Looking for{' '}
16+
<Link to="/login">
17+
<Text style={{ color: '#EDEEF3' }}>Tenant Login</Text>
18+
</Link>
19+
?
20+
</Text>
21+
) : (
22+
<Text style={{ color: '#EDEEF3' }}>
23+
Looking for{' '}
24+
<Link to="/landlord/login">
25+
<Text style={{ color: '#EDEEF3' }}>Landlord Login</Text>
26+
</Link>
27+
?
28+
</Text>
29+
)}
30+
</View>
31+
)
932

1033
const Wrapper = styled(View)`
1134
min-height: 100vh;
@@ -22,103 +45,54 @@ const LogoWrapper = styled(View)`
2245
left: 50px; */
2346
`
2447

25-
const ContentWrapper = styled(View)`
48+
export const ContentWrapper = styled(View)`
2649
flex: 1;
2750
justify-content: space-between;
2851
align-items: center;
2952
margin-bottom: 30px;
3053
`
3154

32-
const FormWrapper = styled(View)`
55+
export const FormWrapper = styled(View)`
3356
flex: 1;
3457
justify-content: center;
3558
align-items: center;
3659
`
3760

38-
const FormRowWrapper = styled(View)`
61+
export const FormRowWrapper = styled(View)`
3962
width: 90%;
4063
flex-direction: row;
4164
justify-content: space-around;
4265
`
4366

4467
const Login = (props: any) => {
45-
const path = props.location.pathname
68+
const isLandlord = props.location.pathname.indexOf('/landlord') !== -1
69+
const path = isLandlord
70+
? props.location.pathname.substring('/landlord'.length)
71+
: props.location.pathname
4672
const { logIn, signUp } = useUserContext()
47-
const [email, setEmail] = React.useState('')
48-
const [password, setPassword] = React.useState('')
49-
const [firstName, setFirstName] = React.useState('')
50-
const [lastName, setLastName] = React.useState('')
5173
return (
5274
<Wrapper>
5375
<LogoWrapper>
5476
<Image source={{ uri: logo }} style={{ width: 180, height: 46 }} />
5577
</LogoWrapper>
56-
<TabBox activeTab={path}>
78+
<TabBox activeTab={path} isLandlord={isLandlord}>
5779
{path === Tabs.login ? (
58-
<ContentWrapper>
59-
<FormWrapper>
60-
<Input
61-
label="Email"
62-
placeholder="you@example.com"
63-
value={email}
64-
onChangeText={setEmail}
65-
style={{ marginBottom: 30 }}
66-
textContentType="emailAddress"
67-
/>
68-
<Input
69-
label="Password"
70-
placeholder="••••••••••"
71-
value={password}
72-
onChangeText={setPassword}
73-
textContentType="password"
74-
secure
75-
/>
76-
</FormWrapper>
77-
<Button onPress={() => logIn(email, password)}>LOGIN</Button>
78-
</ContentWrapper>
80+
<LoginForm
81+
onSubmit={async (email, passowrd) => {
82+
await logIn(email, passowrd, isLandlord)
83+
props.history.push('/')
84+
}}
85+
/>
7986
) : (
80-
<ContentWrapper>
81-
<FormWrapper>
82-
<FormRowWrapper>
83-
<Input
84-
label="First Name"
85-
placeholder="John"
86-
value={firstName}
87-
onChangeText={setFirstName}
88-
style={{ width: '45%', marginBottom: 30 }}
89-
/>
90-
<Input
91-
label="Last Name"
92-
placeholder="Doe"
93-
value={lastName}
94-
onChangeText={setLastName}
95-
style={{ width: '45%', marginBottom: 30 }}
96-
/>
97-
</FormRowWrapper>
98-
<FormRowWrapper>
99-
<Input
100-
label="Email"
101-
placeholder="you@example.com"
102-
value={email}
103-
onChangeText={setEmail}
104-
textContentType="emailAddress"
105-
style={{ width: '45%', marginBottom: 30 }}
106-
/>
107-
<Input
108-
label="Password"
109-
placeholder="••••••••••"
110-
value={password}
111-
onChangeText={setPassword}
112-
textContentType="newPassword"
113-
secure
114-
style={{ width: '45%', marginBottom: 30 }}
115-
/>
116-
</FormRowWrapper>
117-
</FormWrapper>
118-
<Button onPress={() => signUp({ email, password, firstName, lastName })}>SIGNUP</Button>
119-
</ContentWrapper>
87+
<SignupForm
88+
onSubmit={async args => {
89+
await signUp({ ...args, isLandlord })
90+
props.history.push('/')
91+
}}
92+
/>
12093
)}
12194
</TabBox>
95+
<LinkToOtherLogin isLandlord={isLandlord} />
12296
</Wrapper>
12397
)
12498
}

client/src/screens/Login/UserContext.tsx

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@ interface UserContext {
1111
userState: UserState
1212
setUserState: (userState: UserState) => void
1313
getUser: () => void
14-
signUp: (args: { firstName: string; lastName: string; email: string; password: string }) => void
15-
logIn: (username: string, password: string) => void
14+
signUp: (args: {
15+
firstName: string
16+
lastName: string
17+
email: string
18+
password: string
19+
isLandlord: boolean
20+
}) => void
21+
logIn: (username: string, password: string, isLandlord: boolean) => Promise<void>
1622
logOut: () => void
1723
}
1824

@@ -23,7 +29,7 @@ export const UserContext = React.createContext<UserContext>({
2329
setUserState: () => {},
2430
getUser: () => {},
2531
signUp: () => {},
26-
logIn: () => {},
32+
logIn: () => new Promise(() => {}),
2733
logOut: () => {},
2834
})
2935

@@ -49,27 +55,30 @@ export const UserProvider: React.FunctionComponent<{}> = props => {
4955
await getUser()
5056
}
5157

58+
const signUp = async (args: {
59+
firstName: string
60+
lastName: string
61+
email: string
62+
password: string
63+
isLandlord: boolean
64+
}) => {
65+
const { firstName, lastName, email, password } = args
66+
await accountsPassword.createUser({
67+
password,
68+
email,
69+
profile: { firstName, lastName }, // TODO
70+
})
71+
72+
await logIn(email, password)
73+
}
74+
5275
return (
5376
<UserContext.Provider
5477
value={{
5578
userState,
5679
setUserState,
5780
getUser,
58-
signUp: async (args: {
59-
firstName: string
60-
lastName: string
61-
email: string
62-
password: string
63-
}) => {
64-
const { firstName, lastName, email, password } = args
65-
await accountsPassword.createUser({
66-
password,
67-
email,
68-
profile: { firstName, lastName }, // TODO
69-
})
70-
71-
await logIn(email, password)
72-
},
81+
signUp,
7382
logIn,
7483
logOut: async () => {
7584
await accountsGraphQL.logout()
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import * as React from 'react'
2+
import { Formik } from 'formik'
3+
import Button from '../../../components/Button'
4+
import Input from '../../../components/Input'
5+
import { ContentWrapper, FormWrapper } from '../Login'
6+
7+
interface LoginFormProps {
8+
onSubmit: (email: string, password: string) => void
9+
}
10+
11+
const LoginForm = ({ onSubmit }: LoginFormProps) => (
12+
<Formik
13+
initialValues={{ email: '', password: '' }}
14+
validate={values => {
15+
const errors: any = {}
16+
if (!values.email) {
17+
errors.email = 'Required'
18+
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) {
19+
errors.email = 'Invalid email address'
20+
}
21+
if (!values.password) {
22+
errors.password = 'Required'
23+
}
24+
return errors
25+
}}
26+
validateOnBlur={true}
27+
validateOnChange={false}
28+
onSubmit={async (values, { setSubmitting }) => {
29+
try {
30+
await onSubmit(values.email, values.password)
31+
} catch (e) {
32+
console.log('ERROR', e.message)
33+
}
34+
setSubmitting(false)
35+
}}
36+
>
37+
{({
38+
values,
39+
// errors,
40+
// touched,
41+
// handleChange,
42+
handleBlur,
43+
handleSubmit,
44+
setFieldValue,
45+
isSubmitting,
46+
}) => (
47+
<ContentWrapper>
48+
<FormWrapper>
49+
<Input
50+
name="email"
51+
label="Email"
52+
placeholder="you@example.com"
53+
value={values.email}
54+
onChangeText={text => setFieldValue('email', text)}
55+
onBlur={handleBlur}
56+
style={{ marginBottom: 30 }}
57+
textContentType="emailAddress"
58+
/>
59+
<Input
60+
name="password"
61+
label="Password"
62+
placeholder="••••••••••"
63+
value={values.password}
64+
onChangeText={text => setFieldValue('password', text)}
65+
onBlur={handleBlur}
66+
textContentType="password"
67+
secure
68+
/>
69+
</FormWrapper>
70+
<Button onPress={handleSubmit} disabled={isSubmitting}>
71+
LOGIN
72+
</Button>
73+
</ContentWrapper>
74+
)}
75+
</Formik>
76+
)
77+
78+
export default LoginForm

0 commit comments

Comments
 (0)