Carpool(React Native & Express & apollo federation & Mariadb, Mongodb) - 3. 로그인, 회원가입 화면

yellow_note·2021년 12월 7일
0

#1 로그인 화면

로그인 화면 UI를 작성하기 이전에 공통으로 사용될 컴포넌트들을 만들어 보도록 하겠습니다.

  • ./src/screens/common/BorderButton.js
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
import styles from './styles/styled.border.button';

const BorderButton = ({
    text,
    onPress
}) => {
    return(
        <TouchableOpacity style={ styles.button }
                          onPress={ onPress }
        >
            <Text style={ styles.text }>{ text }</Text>
        </TouchableOpacity>
    );
};

export default BorderButton;
  • ./src/screens/common/styles/border.button.js
import { StyleSheet } from "react-native";
import palette from "../../../utils/palette";

const styles = StyleSheet.create({
    button: {
        width: 300,
        height: 40,
        borderRadius: 30,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: palette.white[0],
        borderColor: palette.sky[0],
        borderWidth: 2,
        margin: 10,
    },
    text: {
        fontSize: 15,
        color: palette.sky[0],
    }
});

export default styles;
  • ./src/screens/common/FullButton.js
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
import styles from './styles/styled.full.button';

const FullButton = ({
    onPress,
    text
}) => {
    return(
        <TouchableOpacity style={ styles.button }
                          onPress={ onPress }
        >
            <Text style={ styles.text }>
                { text }
            </Text>
        </TouchableOpacity>
    );
};

export default FullButton;
  • ./src/screens/common/styles/styled.full.button.js
import { StyleSheet } from "react-native";
import palette from "../../../utils/palette";

const styles = StyleSheet.create({
    button: {
        width: 300,
        height: 40,
        borderRadius: 30,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: palette.sky[0],
        margin: 10,
    },
    text: {
        fontSize: 15,
        color: palette.white[0],
    },
});

export default styles;
  • ./src/screens/common/BottomlineInput.js
import React from 'react';
import { TextInput } from 'react-native';
import styles from './styles/styled.bottomline.input';

const BottomlineInput = ({
    inputAccessoryViewID,
    placeholder,
    placeholderTextColor,
    onChange,
    value
}) => {
    return <TextInput style={ styles.input }
                      inputAccessoryViewID={ inputAccessoryViewID }
                      placeholder={ placeholder }
                      placeholderTextColor={ placeholderTextColor }
                      onChange={ onChange }
                      value={ value }
           />;
};

export default BottomlineInput;
  • ./src/screens/common/styles/bottomline.input.js
import { StyleSheet } from "react-native";
import palette from "../../../utils/palette";

const styles = StyleSheet.create({
    input: {
        width: 300,
        height: 40,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: palette.white[0],
        borderBottomColor: palette.sky[0],
        borderBottomWidth: 1,
        fontSize: 15,
        margin: 10,
    },
});

export default styles;

앞으로 사용할 공통 버튼, 인풋 컴포넌트를 작성했습니다. 그러면 이 컴포넌트들을 가지고 로그인화면을 작성해보도록 하겠습니다.

위의 화면을 토대로 작성을 진행하겠습니다.

  • ./src/screens/auth/components/LoginForm.js
import React from 'react';
import { CommonActions, useNavigation } from '@react-navigation/native';
import { View } from 'react-native';
import palette from '../../../utils/palette';
import FullButton from '../../common/FullButton';
import BorderButton from '../../common/BorderButton';
import BottomlineInput from '../../common/BottomlineInput';
import styles from '../styles/login';

const LoginForm = () => {
    const navigation = useNavigation();
    const toMainScreen = e => {
        navigation.dispatch(CommonActions.reset({
            routes: [{ name: 'BottomNavigator' }]
        }));
    };
    const toSignupScreen = e => {
        navigation.navigate('SignupScreen');
    };

    return (
        <View style={ styles.login_form }>
            <BottomlineInput inputAccessoryViewID="email"
                             placeholder="E-mail"
                             placeholderTextColor={ palette.gray[4] }
            />
            <BottomlineInput inputAccessoryViewID="password"
                             placeholder="Password"
                             placeholderTextColor={ palette.gray[4] }
            />
            <FullButton text="Signin"
                        onPress={ toMainScreen }
            />
            <BorderButton text="Signup"
                          onPress={ toSignupScreen }
            />
        </View>
    );
};

export default LoginForm;
  • ./src/screens/auth/LoginScreen.js
import React from 'react';
import { View } from 'react-native';
import LoginForm from './components/LoginForm';
import styles from './styles/login';

const LoginScreen = () => {
    return(
        <View style={ styles.login_screen }>
            <LoginForm />
        </View>
    );
};

export default LoginScreen;
  • ./src/screens/auth/styles/login.js
import { StyleSheet } from "react-native";
import palette from "../../../utils/palette";

const styles = StyleSheet.create({
    login_screen: {
        flex: 1,
        backgroundColor: palette.white[0]
    },
    login_form: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center'
    }
});

export default styles;

로그인 스큰린를 완성했습니다. 이어서 회원가입 화면을 구현하도록 하겠습니다.

#2 회원가입 화면

위의 화면을 토대로 회원가입 화면을 작성하기 이전에 회원가입 상단 문구 컴포넌트를 작성하도록 하겠습니다.

  • ./src/screens/auth/components/NoticeText.js
import React from 'react';
import { Text, View } from 'react-native';
import styles from '../styles/register';

const NoticeText = ({ text }) => {
    return (
        <Text style={ styles.normal_font_18 }>
            { text }
        </Text>
    );
};

export default NoticeText;

문구를 작성했으니 회원가입 폼을 작성하도록 하겠습니다.

  • ./src/screens/auth/components/RegisterForm.js
import React from 'react';
import { View } from 'react-native';
import BottomlineInput from '../../common/BottomlineInput';
import palette from '../../../utils/palette';
import styles from '../styles/register';

const RegisterForm = () => {
    return(
        <View style={ styles.register_form }>
            <BottomlineInput inputAccessoryViewID="email"
                             placeholder="E-mail"
                             placeholderTextColor={ palette.gray[5] }
            />
            <BottomlineInput inputAccessoryViewID="password"
                             placeholder="Password"
                             placeholderTextColor={ palette.gray[5] }
            />
            <BottomlineInput inputAccessoryViewID="passwordConfirm"
                             placeholder="Re-password"
                             placeholderTextColor={ palette.gray[5] }
            />
            <BottomlineInput inputAccessoryViewID="nickname"
                             placeholder="Nickname"
                             placeholderTextColor={ palette.gray[5] }
            />
        </View>
    );
};

export default RegisterForm;
  • ./src/screens/auth/RegisterHeader.js
import React from 'react';
import { View } from 'react-native';
import styles from '../styles/register';
import NoticeText from './NoticeText';

const RegisterHeader = () => {
    return (
        <View style={ styles.register_header }>
            <NoticeText text={ "회원가입을 위한 \n기본정보를 입력해주세요!" }/>
        </View>
    );
};

export default RegisterHeader;
  • ./src/screens/auth/RegisterFooter.js
import { useNavigation } from '@react-navigation/native';
import React from 'react';
import { View } from 'react-native';
import FullButton from '../../common/FullButton';
import styles from '../styles/register';

const RegisterFooter = () => {
    const navigation = useNavigation();
    const toLicenseScreen = e => {
        navigation.navigate('LicenseScreen');
    };

    return (
        <View style={ styles.register_footer }>
            <FullButton onPress={ toLicenseScreen }
                        text="Next"
            />
        </View>
    )
};

export default RegisterFooter;

Footer에 버튼을 배치한 이유는 추후에 Input state을 관리할 리듀서를 만들어 사용하기 위함입니다.

  • ./src/screens/auth/RegisterScreen.js
import React from 'react';
import { View } from 'react-native';
import RegisterFooter from './components/RegisterFooter';
import RegisterForm from './components/RegisterForm';
import RegisterHeader from './components/RegisterHeader';
import styles from './styles/register';

const RegisterScreen = () => {
    return(
        <View style={ styles.register_screen }>
            <RegisterHeader />
            <RegisterForm />
            <RegisterFooter />
        </View>
    );
};

export default RegisterScreen;
  • ./src/screens/auth/styles/register.js
import { StyleSheet } from "react-native";
import palette from "../../../utils/palette";

const styles = StyleSheet.create({
    register_screen: {
        flex: 1,
        backgroundColor: palette.white[0]
    },
    register_header: {
        flex: 0.2,
        paddingLeft: 45,
        justifyContent: 'flex-end',
        alignItems: 'flex-start',
    },
    register_form: {
        flex: 0.5,
        justifyContent: 'center',
        alignItems: 'center',
    },
    register_footer: {
        flex: 0.1,
        justifyContent: 'center',
        alignItems: 'center'
    },
});

export default styles;

이 부분까지는 기본 회원 가입에 필요한 내용이고 이 후에 작성될 컴포넌트는 운전자 등록을 할 경우 필요한 컴포넌트입니다.

  • ./src/screens/auth/components/LicenseForm.js
import React from 'react';
import { View } from 'react-native';
import BottomlineInput from '../../common/BottomlineInput';
import styles from '../styles/register';
import FullButton from '../../common/FullButton';
import NoticeText from './NoticeText';
import { CommonActions, useNavigation } from '@react-navigation/native';
import palette from '../../../utils/palette';

const LicenseForm = () => {
    const navigation = useNavigation();
    const toSigninScreen = e => {
        navigation.dispatch(CommonActions.reset({
            routes: [{ name: 'SigninScreen' }]
        }));
    };

    return (
        <View style={ styles.license_form }>
            <NoticeText text={ "운전자 등록 화면입니다. \n등록을 하시려면 사항들을 기입해주세요. \n미등록의 경우 가입 버튼을 눌러주세요!" } />
            <BottomlineInput inputAccessoryViewID="birthDate"
                             placeholder="Birth Date"
                             placeholderTextColor={ palette.gray[5] }
            />
            <BottomlineInput inputAccessoryViewID="name"
                             placeholder="Name"
                             placeholderTextColor={ palette.gray[5] }
            />
            <BottomlineInput inputAccessoryViewID="licNumber"
                             placeholder="License Number"
                             placeholderTextColor={ palette.gray[5] }
            />
            <FullButton text="Signup" 
                        onPress={ toSigninScreen }
            />
        </View>
    );
};

export default LicenseForm;
  • ./src/screens/auth/components/LicenseHeader.js
import React from 'react';
import { View } from 'react-native';
import styles from '../styles/register';
import NoticeText from './NoticeText';

const LicenseHeader = () => {
    return (
        <View style={ styles.license_header }>
            <NoticeText text={ "운전자 등록 화면입니다. \n등록을 하시려면 사항들을 기입해주세요. \n미등록의 경우 가입 버튼을 눌러주세요!" } />
        </View>
    );
};

export default LicenseHeader;
  • ./src/screens/auth/components/LicenseFooter.js
import { CommonActions, useNavigation } from '@react-navigation/native';
import React from 'react';
import { View } from 'react-native';
import BorderButton from '../../common/BorderButton';
import FullButton from '../../common/FullButton';
import styles from '../styles/register';

const LicenseFooter = () => {
    const navigation = useNavigation();
    const onDriverRegister = e => {
        navigation.dispatch(CommonActions.reset({
            routes: [{ name: 'SigninScreen' }]
        }));
    };
    const onPassengerRegister = e => {
        navigation.dispatch(CommonActions.reset({
            routes: [{ name: 'SigninScreen' }]
        }));
    };

    return (
        <View style={ styles.license_footer }>
            <FullButton text="For Driver" 
                        onPress={ onDriverRegister }
            />
            <BorderButton text="For Passenger"
                          onPress={ onPassengerRegister }
            />
        </View>
    );
};

export default LicenseFooter;

License 스크린도 마찬가지로 회원가입의 state로써 input값들을 관리합니다.

  • ./src/screens/auth/LicenseScreen.js
import React from 'react';
import { View } from 'react-native';
import styles from './styles/register';
import LicenseForm from './components/LicenseForm';
import LicenseHeader from './components/LicenseHeader';
import LicenseFooter from './components/LicenseFooter';

const LicenseScreen = () => {
    return (
        <View style={ styles.license_screen }>
            <LicenseHeader />
            <LicenseForm />
            <LicenseFooter />
        </View>
    );
};

export default LicenseScreen;
  • ./src/screens/auth/styles/register.js
import { StyleSheet } from "react-native";
import palette from "../../../utils/palette";

const styles = StyleSheet.create({
    ...
    license_screen: {
        flex: 1,
        backgroundColor: palette.white[0]
    },
    license_header: {
        flex: 0.2,
        paddingLeft: 45,
        justifyContent: 'flex-end',
        alignItems: 'flex-start',
    },
    license_form: {
        flex: 0.5,
        justifyContent: 'center',
        alignItems: 'center',
    },
    license_footer: {
        flex: 0.1,
        justifyContent: 'center',
        alignItems: 'center'
    },
    normal_font_18: {
        fontSize: 18,
    },
});

export default styles;

#3 네비게이션 추가 및 테스트

로그인, 회원가입 관련 페이지를 첫 화면으로 설정하기 위해 MainNavigator에 컴포넌트를 추가하도록 하겠습니다.

  • ./src/navigator/MainNavigator.js
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import { NavigationContainer } from '@react-navigation/native';
import BottomNavigator from './BottomNavigator';
import LoginScreen from '../screens/auth/LoginScreen';
import RegisterScreen from '../screens/auth/RegisterScreen';
import LicenseScreen from '../screens/auth/LicenseScreen';

const Stack = createStackNavigator();
const MainNavigator = () => {
    return (
        <NavigationContainer>
            <Stack.Navigator>
                <Stack.Screen name="SigninScreen"
                              component={ LoginScreen }
                              options={{ headerShown: false }}
                />        
                <Stack.Screen name="SignupScreen"
                              component={ RegisterScreen }
                />  
                <Stack.Screen name="LicenseScreen"
                              component={ LicenseScreen }
                />
                <Stack.Screen name="BottomNavigator"
                              component={ BottomNavigator }
                              options={{ headerShown: false }}
                />
            </Stack.Navigator>
        </NavigationContainer>
    );
};

export default MainNavigator;

MainNavigator에 앞서 작성한 스크린들을 추가했으니 테스트를 진행해보도록 하겠습니다.



테스트 결과 화면이 잘 나오는 모습을 볼 수 있습니다. 다음 포스트에서는 백엔드 auth-service를 작성하도록 하겠습니다.

0개의 댓글

관련 채용 정보