240 lines
No EOL
9 KiB
JavaScript
240 lines
No EOL
9 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import * as Notifications from 'expo-notifications';
|
|
import { router } from 'expo-router';
|
|
import { createUserWithEmailAndPassword, updateProfile } from 'firebase/auth';
|
|
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}`
|
|
});
|
|
// Request permissions and get push token (native FCM if possible, else Expo token)
|
|
let token = null;
|
|
let tokenType = null;
|
|
const { status: existingStatus } = await Notifications.getPermissionsAsync();
|
|
let finalStatus = existingStatus;
|
|
if (existingStatus !== 'granted') {
|
|
const { status } = await Notifications.requestPermissionsAsync();
|
|
finalStatus = status;
|
|
}
|
|
if (finalStatus === 'granted') {
|
|
try {
|
|
// Try to get native FCM token (works in dev/prod builds, not Expo Go)
|
|
const deviceToken = await Notifications.getDevicePushTokenAsync({ provider: 'fcm' });
|
|
if (deviceToken?.data) {
|
|
token = deviceToken.data;
|
|
tokenType = 'fcm';
|
|
} else {
|
|
// Fallback to Expo push token
|
|
const expoToken = await Notifications.getExpoPushTokenAsync();
|
|
token = expoToken.data;
|
|
tokenType = 'expo';
|
|
}
|
|
} catch (e) {
|
|
// Fallback to Expo push token if native fails
|
|
const expoToken = await Notifications.getExpoPushTokenAsync();
|
|
token = expoToken.data;
|
|
tokenType = 'expo';
|
|
}
|
|
}
|
|
|
|
await postgresServices.createUser({
|
|
firstName: values.firstName,
|
|
lastName: values.lastName,
|
|
number: values.number,
|
|
email: values.email,
|
|
provider: values.provider,
|
|
departments: [],
|
|
token,
|
|
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>
|
|
)
|
|
} |