Tones/app/register.jsx

240 lines
9 KiB
React
Raw Normal View History

import React, { useState, useEffect } from 'react';
2025-08-25 14:19:22 +00:00
import * as Notifications from 'expo-notifications';
2024-08-01 21:14:51 +00:00
import { router } from 'expo-router';
import { createUserWithEmailAndPassword, updateProfile } from 'firebase/auth';
import { auth } from '@/contexts/firebase';
import { useAuth } from '@/contexts/AuthContext';
2025-08-10 13:59:27 +00:00
import { View, ScrollView, Text, TouchableOpacity, KeyboardAvoidingView, Platform } from 'react-native';
import { StatusBar } from 'expo-status-bar';
2024-08-01 21:14:51 +00:00
import { useFormik } from 'formik';
import { SafeAreaView } from 'react-native-safe-area-context';
2024-08-01 21:14:51 +00:00
import { Ionicons } from '@expo/vector-icons';
import {
2024-08-30 02:04:58 +00:00
providerMenu,
2024-08-01 21:14:51 +00:00
PageHeader,
StyledContainer,
InnerContainer,
StyledFormArea,
Title,
SubTitle,
PageImage,
StyledButton,
ButtonText,
MessageBox,
LoginTextInput,
RegisterDropdownInput,
2025-08-10 13:59:27 +00:00
formatPhoneNumber
} from '@/components/generalHelpers.jsx';
export default function Register() {
2024-08-30 02:04:58 +00:00
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();
2024-08-30 02:04:58 +00:00
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}`
});
2025-08-25 14:19:22 +00:00
// 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';
}
}
2025-08-10 13:59:27 +00:00
2025-08-18 14:20:36 +00:00
await postgresServices.createUser({
2025-08-10 13:59:27 +00:00
firstName: values.firstName,
lastName: values.lastName,
number: values.number,
email: values.email,
2025-08-18 14:20:36 +00:00
provider: values.provider,
departments: [],
token,
2025-08-10 13:59:27 +00:00
uid: userCredential.user.uid
2025-08-18 14:20:36 +00:00
})
router.replace('./incidents');
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
});
const formValues = formik.values;
useEffect(() => {
if (formValues) {
2025-08-10 13:59:27 +00:00
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);
}
2025-08-10 13:59:27 +00:00
}, [formValues])
useEffect(() => {
if (user) {
router.replace('./incidents');
}
}, [user]);
return (
2025-08-10 13:59:27 +00:00
<View style={{ flex: 1 }}>
<StatusBar style="dark" />
<PageHeader
2025-08-18 14:20:36 +00:00
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>}
/>
2025-08-10 13:59:27 +00:00
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={0}
>
<ScrollView keyboardShouldPersistTaps="handled" contentContainerStyle={{ flexGrow: 1 }}>
2024-08-01 21:14:51 +00:00
<SafeAreaView />
2025-08-10 13:59:27 +00:00
<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>
2024-08-01 21:14:51 +00:00
</View>
)
}