Add Keyboard fixes & Realtime Database

This commit is contained in:
Matt DiMeglio 2025-08-10 09:59:27 -04:00
parent 1368369495
commit 0a857f86a7
4 changed files with 219 additions and 164 deletions

View file

@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { View, Text } from 'react-native';
import { View, Text, ScrollView, KeyboardAvoidingView, Platform } from 'react-native';
import { StatusBar } from 'expo-status-bar';
import { useFormik } from 'formik';
import { SafeAreaView } from 'react-native-safe-area-context';
@ -65,12 +65,18 @@ export default function Login() {
}, [formValues]);
return (
<React.Fragment>
<View style={{ flex: 1 }}>
<StatusBar style="dark" />
<PageHeader>
<View style={{ flexDirection: 'row', height: 80, alignItems: 'center' }} />
</PageHeader>
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={0}
>
<ScrollView keyboardShouldPersistTaps="handled" contentContainerStyle={{ flexGrow: 1 }}>
<StyledContainer>
<StatusBar style="dark" />
<SafeAreaView />
<InnerContainer>
<PageImage resizeMode="cover" source={require('./../assets/images/tones-logo.png')} />
@ -87,6 +93,8 @@ export default function Login() {
onBlur={formik.handleBlur('email')}
value={formik.values.email}
keyboardType="email-address"
autoComplete='email'
autoCapitalize='none'
/>
<LoginTextInput
label="Password"
@ -102,7 +110,7 @@ export default function Login() {
setHidePassword={setHidePassword}
/>
<MessageBox>...</MessageBox>
<StyledButton onPress={formik.handleSubmit} disabled={loginButtonDisabled} style={loginButtonDisabled ? {backgroundColor: 'grey'} : {}}>
<StyledButton onPress={formik.handleSubmit} disabled={loginButtonDisabled} style={loginButtonDisabled ? { backgroundColor: 'grey' } : {}}>
<ButtonText>Login</ButtonText>
</StyledButton>
<Line />
@ -127,6 +135,8 @@ export default function Login() {
<Line />
</InnerContainer>
</StyledContainer>
</React.Fragment>
</ScrollView>
</KeyboardAvoidingView>
</View>
);
}
}

View file

@ -1,9 +1,10 @@
import React, { useState, useEffect } from 'react';
import { router } from 'expo-router';
import { createUserWithEmailAndPassword, updateProfile } from 'firebase/auth';
import { getDatabase, ref, set } from 'firebase/database';
import { auth } from '@/contexts/firebase';
import { useAuth } from '@/contexts/AuthContext';
import { View, ScrollView, Text, TouchableOpacity } from 'react-native';
import { View, ScrollView, Text, TouchableOpacity, KeyboardAvoidingView, Platform } from 'react-native';
import { StatusBar } from 'expo-status-bar';
import { useFormik } from 'formik';
import { SafeAreaView } from 'react-native-safe-area-context';
@ -22,7 +23,8 @@ import {
MessageBox,
LoginTextInput,
RegisterDropdownInput,
} from '../components/generalHelpers.jsx';
formatPhoneNumber
} from '@/components/generalHelpers.jsx';
export default function Register() {
const [providerDropdownOpen, setProviderDropdownOpen] = useState(false);
@ -50,6 +52,16 @@ export default function Register() {
await updateProfile(userCredential.user, {
displayName: `${values.firstName} ${values.lastName}`
});
const db = getDatabase();
await set(ref(db, 'users/' + userCredential.user.uid), {
firstName: values.firstName,
lastName: values.lastName,
number: values.number,
provider: values.provider,
email: values.email,
uid: userCredential.user.uid
});
router.replace('./incidents');
} catch (err) {
setError(err.message);
@ -63,13 +75,9 @@ export default function Register() {
useEffect(() => {
if (formValues) {
if (
formValues.email &&
formValues.firstName &&
formValues.lastName &&
formValues.password.length !== 0 &&
formValues.password === formValues.passwordConfirmation
) {
const regex = /^[^@]+@(?:[a-zA-Z0-9-]+\.)+[a-zA-Z0-9-]+$/;
if ((formValues.number.length === 14 || (formValues.number.length === 10 && !formValues.number.includes('('))) && regex.test(formValues.email) && formValues.firstName && formValues.lastName) {
if (formValues.password.length !== 0 && (formValues.password === formValues.passwordConfirmation)) {
setRegisterButtonDisabled(false);
} else {
setRegisterButtonDisabled(true);
@ -77,7 +85,10 @@ export default function Register() {
} else {
setRegisterButtonDisabled(true);
}
}, [formValues]);
} else {
setRegisterButtonDisabled(true);
}
}, [formValues])
useEffect(() => {
if (user) {
@ -86,7 +97,8 @@ export default function Register() {
}, [user]);
return (
<View>
<View style={{ flex: 1 }}>
<StatusBar style="dark" />
<PageHeader>
<View style={{ flexDirection: 'row', height: 80, alignItems: 'flex-end' }}>
<TouchableOpacity onPress={router.back} style={{ flexDirection: 'row', alignItems: 'center', paddingBottom: 5 }}>
@ -95,10 +107,14 @@ export default function Register() {
</TouchableOpacity>
</View>
</PageHeader>
<ScrollView>
<StyledContainer>
<StatusBar style="dark" />
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={0}
>
<ScrollView keyboardShouldPersistTaps="handled" contentContainerStyle={{ flexGrow: 1 }}>
<SafeAreaView />
<StyledContainer>
<InnerContainer>
<PageImage resizeMode="cover" source={require('./../assets/images/tones-logo.png')} />
{error ? <MessageBox style={{ color: 'red' }}>{error}</MessageBox> : null}
@ -130,8 +146,9 @@ export default function Register() {
placeholderTextColor="gray"
onChangeText={formik.handleChange('number')}
onBlur={formik.handleBlur('number')}
value={formik.values.number.replace(/^(\d{3})(\d{3})(\d+)$/, "($1) $2-$3")}
keyboardType="number-pad"
value={formatPhoneNumber(formik.values.number)}
autoComplete='tel'
keyboardType='phone-pad'
maxLength={14}
/>
<RegisterDropdownInput
@ -151,6 +168,8 @@ export default function Register() {
onBlur={formik.handleBlur('email')}
value={formik.values.email}
keyboardType="email-address"
autoComplete='email'
autoCapitalize='none'
/>
<LoginTextInput
label="Password"
@ -179,13 +198,14 @@ export default function Register() {
setHidePassword={setHidePassword}
/>
<MessageBox>...</MessageBox>
<StyledButton onPress={formik.handleSubmit} style={registerButtonDisabled ? {backgroundColor: 'grey'} : {}}>
<StyledButton onPress={formik.handleSubmit} style={registerButtonDisabled ? { backgroundColor: 'grey' } : {}}>
<ButtonText>Register</ButtonText>
</StyledButton>
</StyledFormArea>
</InnerContainer>
</StyledContainer>
</ScrollView>
</KeyboardAvoidingView>
</View>
)
}

View file

@ -337,3 +337,27 @@ export const RegisterDropdownInput = ({
</Container>
)
}
export const formatPhoneNumber = (e) => {
let formattedNumber;
const length = e?.length;
const regex = () => e.replace(/[^0-9\.]+/g, "");
const areaCode = () => `(${regex().slice(0, 3)})`;
const firstSix = () => `${areaCode()} ${regex().slice(3, 6)}`;
const trailer = (start) => `${regex().slice(start, regex().length)}`;
if (length <= 3) {
formattedNumber = regex();
} else if (length === 4) {
formattedNumber = `${areaCode()} ${trailer(3)}`;
} else if (length === 5) {
formattedNumber = `${areaCode().replace(")", "")}`;
} else if (length >= 5 && length <= 9) {
formattedNumber = `${areaCode()} ${trailer(3)}`;
} else if (length >= 10) {
formattedNumber = `${firstSix()}-${trailer(6)}`;
}
return formattedNumber;
};

View file

@ -5,6 +5,7 @@ import ReactNativeAsyncStorage from '@react-native-async-storage/async-storage';
const firebaseConfig = {
apiKey: process.env.EXPO_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.EXPO_PUBLIC_FIREBASE_DATABASE_URL,
projectId: process.env.EXPO_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,