Introduces Unicode-safe base64 encoding/decoding for call details between incidents and call screens. Refactors PageHeader to accept left, center, and right header props for more flexible layouts. Updates call.jsx and register.jsx to use the new header structure, and improves department/unit rendering and modal dropdowns for department selection. Generalizes and modernizes UI code for better maintainability and cross-platform compatibility.
209 lines
No EOL
7.8 KiB
JavaScript
209 lines
No EOL
7.8 KiB
JavaScript
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, KeyboardAvoidingView, Platform } from 'react-native';
|
|
import { StatusBar } from 'expo-status-bar';
|
|
import { useFormik } from 'formik';
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import {
|
|
providerMenu,
|
|
PageHeader,
|
|
StyledContainer,
|
|
InnerContainer,
|
|
StyledFormArea,
|
|
Title,
|
|
SubTitle,
|
|
PageImage,
|
|
StyledButton,
|
|
ButtonText,
|
|
MessageBox,
|
|
LoginTextInput,
|
|
RegisterDropdownInput,
|
|
formatPhoneNumber
|
|
} from '@/components/generalHelpers.jsx';
|
|
|
|
export default function Register() {
|
|
const [providerDropdownOpen, setProviderDropdownOpen] = useState(false);
|
|
const [hidePassword, setHidePassword] = useState(true);
|
|
const [registerButtonDisabled, setRegisterButtonDisabled] = useState(true);
|
|
const [error, setError] = useState('');
|
|
const [loading, setLoading] = useState(false);
|
|
const { user } = useAuth();
|
|
|
|
const formik = useFormik({
|
|
initialValues: {
|
|
firstName: '',
|
|
lastName: '',
|
|
number: '',
|
|
provider: '',
|
|
email: '',
|
|
password: '',
|
|
passwordConfirmation: ''
|
|
},
|
|
onSubmit: async (values) => {
|
|
setError('');
|
|
setLoading(true);
|
|
try {
|
|
const userCredential = await createUserWithEmailAndPassword(auth, values.email, values.password);
|
|
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);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
});
|
|
|
|
const formValues = formik.values;
|
|
|
|
useEffect(() => {
|
|
if (formValues) {
|
|
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);
|
|
}
|
|
} else {
|
|
setRegisterButtonDisabled(true);
|
|
}
|
|
} else {
|
|
setRegisterButtonDisabled(true);
|
|
}
|
|
}, [formValues])
|
|
|
|
useEffect(() => {
|
|
if (user) {
|
|
router.replace('./incidents');
|
|
}
|
|
}, [user]);
|
|
|
|
return (
|
|
<View style={{ flex: 1 }}>
|
|
<StatusBar style="dark" />
|
|
<PageHeader
|
|
leftHeader={ <TouchableOpacity onPress={router.back} style={{ flexDirection: 'row', alignItems: 'center', paddingBottom: 5 }}>
|
|
<Ionicons name="chevron-back-outline" size={22} color="red" style={{ paddingLeft: 20 }} />
|
|
<Text style={{ color: 'red', fontWeight: 600 }}>Back to Login</Text>
|
|
</TouchableOpacity>}
|
|
/>
|
|
<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}
|
|
<Title>Tones</Title>
|
|
<SubTitle>Account Register</SubTitle>
|
|
<StyledFormArea>
|
|
<LoginTextInput
|
|
label="First Name"
|
|
icon="person-outline"
|
|
placeholder="Bud"
|
|
placeholderTextColor="gray"
|
|
onChangeText={formik.handleChange('firstName')}
|
|
onBlur={formik.handleBlur('firstName')}
|
|
value={formik.values.firstName}
|
|
/>
|
|
<LoginTextInput
|
|
label="Last Name"
|
|
icon="people-outline"
|
|
placeholder="Doble"
|
|
placeholderTextColor="gray"
|
|
onChangeText={formik.handleChange('lastName')}
|
|
onBlur={formik.handleBlur('lastName')}
|
|
value={formik.values.lastName}
|
|
/>
|
|
<LoginTextInput
|
|
label="Phone Number"
|
|
icon="call-outline"
|
|
placeholder="123-456-7890"
|
|
placeholderTextColor="gray"
|
|
onChangeText={formik.handleChange('number')}
|
|
onBlur={formik.handleBlur('number')}
|
|
value={formatPhoneNumber(formik.values.number)}
|
|
autoComplete='tel'
|
|
keyboardType='phone-pad'
|
|
maxLength={14}
|
|
/>
|
|
<RegisterDropdownInput
|
|
label="Cellular Provider"
|
|
isOpen={providerDropdownOpen}
|
|
setOpen={setProviderDropdownOpen}
|
|
selectedValue={formik.values.provider}
|
|
onValueChange={formik.handleChange('provider')}
|
|
menu={providerMenu}
|
|
/>
|
|
<LoginTextInput
|
|
label="Email Address"
|
|
icon="mail-outline"
|
|
placeholder="test@organization.com"
|
|
placeholderTextColor="gray"
|
|
onChangeText={formik.handleChange('email')}
|
|
onBlur={formik.handleBlur('email')}
|
|
value={formik.values.email}
|
|
keyboardType="email-address"
|
|
autoComplete='email'
|
|
autoCapitalize='none'
|
|
/>
|
|
<LoginTextInput
|
|
label="Password"
|
|
icon="lock-closed-outline"
|
|
placeholder="* * * * * *"
|
|
placeholderTextColor="gray"
|
|
onChangeText={formik.handleChange('password')}
|
|
onBlur={formik.handleBlur('password')}
|
|
value={formik.values.password}
|
|
secureTextEntry={hidePassword}
|
|
isPassword
|
|
hidePassword={hidePassword}
|
|
setHidePassword={setHidePassword}
|
|
/>
|
|
<LoginTextInput
|
|
label="Confirm Password"
|
|
icon="shield-checkmark-outline"
|
|
placeholder="* * * * * *"
|
|
placeholderTextColor="gray"
|
|
onChangeText={formik.handleChange('passwordConfirmation')}
|
|
onBlur={formik.handleBlur('passwordConfirmation')}
|
|
value={formik.values.passwordConfirmation}
|
|
secureTextEntry={hidePassword}
|
|
isPassword
|
|
hidePassword={hidePassword}
|
|
setHidePassword={setHidePassword}
|
|
/>
|
|
<MessageBox>...</MessageBox>
|
|
<StyledButton onPress={formik.handleSubmit} style={registerButtonDisabled ? { backgroundColor: 'grey' } : {}}>
|
|
<ButtonText>Register</ButtonText>
|
|
</StyledButton>
|
|
</StyledFormArea>
|
|
</InnerContainer>
|
|
</StyledContainer>
|
|
</ScrollView>
|
|
</KeyboardAvoidingView>
|
|
</View>
|
|
)
|
|
} |