본문 바로가기
React.js/SNS Project

Day 3

by Jinny96 2022. 8. 22.

1. 폴더 구조


2. 로딩 화면

-Loader.jsx

import "./Loader.css";

const Loader = () => {
    return (
        <div className="loader loader-default is-active"></div>
    )
}

export default Loader;

비동기 처리할 때 유저에게 보여줄 로딩 화면이다.

 

 

-Loader.css

코드가 너무 길어 첨부하진 않겠다.


3. Firebase Firestore 연동

-Firebase.js

import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";

const firebaseConfig = {
  apiKey: "",
  authDomain: "youngstagram-e6806.firebaseapp.com",
  projectId: "youngstagram-e6806",
  storageBucket: "youngstagram-e6806.appspot.com",
  messagingSenderId: "72953816598",
  appId: "",
  measurementId: "G-J2YNTMENVF"
};

const app = initializeApp(firebaseConfig);
export const auth = getAuth(); // Firebase Authentication
export const db = getFirestore(app); // Firebase Firestore

4. 회원가입 페이지

-SignUp.jsx

import { useState } from "react";
import { useNavigate } from 'react-router-dom';

import { Box, Button, Grid, TextField, Typography } from "@mui/material";
import InstagramIcon from '@mui/icons-material/Instagram';

import Swal from 'sweetalert2';

import { collection, addDoc } from "firebase/firestore";
import { createUserWithEmailAndPassword } from "firebase/auth";

import { auth, db } from "../Env/Firebase";
import Loader from "../Env/Loader";

const SignUp = () => {
    const navigate = useNavigate();
    const [isLoading, setIsLoading] = useState(false);
    const [name, setName] = useState("");
    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");

    const onChange = (event) => {
        const { target: { id, value } } = event;
        if (id === "name") {
            setName(value);
        } else if (id === "email") {
            setEmail(value)
        } else if (id === "password") {
            setPassword(value)
        }
    }

    const onClickSignUp = () => {
        if (!name || !email || !password) {
            Swal.fire({
                icon: 'error',
                title: '회원가입 실패',
                html: "모두 작성해주세요.",
                showClass: {
                    popup: 'animate__animated animate__fadeInDown'
                },
                hideClass: {
                    popup: 'animate__animated animate__fadeOutUp'
                }
            });
        } else {
            setIsLoading(true);
            createUserWithEmailAndPassword(auth, email, password).then(async (res) => {
                try {
                    await addDoc(collection(db, "users"), {
                        id: res._tokenResponse.localId,
                        email: email,
                        name: name,
                        image: "",
                        count_feed: 0,
                        introduce: ""
                    }).then(() => {
                        setIsLoading(false);
                        Swal.fire({
                            icon: 'success',
                            title: '회원가입 완료',
                            html: '회원가입이 정상적으로 완료되었습니다.',
                            showClass: {
                                popup: 'animate__animated animate__fadeInDown'
                            },
                            hideClass: {
                                popup: 'animate__animated animate__fadeOutUp'
                            }
                        }).then(() => {
                            sessionStorage.setItem("user_id", res._tokenResponse.localId);
                            navigate("/home");
                        });
                    });
                } catch (e) {
                    setIsLoading(false);
                    Swal.fire({
                        icon: 'error',
                        title: '회원가입 실패',
                        html: "다시 시도해주세요.",
                        showClass: {
                            popup: 'animate__animated animate__fadeInDown'
                        },
                        hideClass: {
                            popup: 'animate__animated animate__fadeOutUp'
                        }
                    });
                }
            }).catch(() => {
                setIsLoading(false);
                Swal.fire({
                    icon: 'error',
                    title: '회원가입 실패',
                    html: "다시 시도해주세요.",
                    showClass: {
                        popup: 'animate__animated animate__fadeInDown'
                    },
                    hideClass: {
                        popup: 'animate__animated animate__fadeOutUp'
                    }
                });
            });
        }
    }

    if (isLoading) return <Loader />

    return (
        <Box
            style={{
                width: 350,
                height: "100vh",
                alignItems: "center",
                display: "flex",
                textAlign: "center",
                margin: "auto"
            }}
        >
            <Grid container>
                <Grid item xs={12}>
                    <Grid item xs={12}>
                        <InstagramIcon fontSize="large" style={{ color: "black" }} />
                    </Grid>
                    <Grid item xs={12}>
                        <Typography variant="h4" style={{ color: "black" }}>
                            Youngstagram
                    </Typography>
                    </Grid>
                    <Grid item xs={12} style={{ marginTop: 10 }}>
                        <Typography variant="subtitle1" style={{ color: "grey" }}>
                            가입하고 우리만의 추억을 공유해봐요.
                    </Typography>
                    </Grid>
                </Grid>
                <Grid item xs={12} style={{ marginTop: 50 }}>
                    <TextField
                        id="name"
                        label="Name"
                        value={name}
                        variant="outlined"
                        sx={{
                            "& .MuiInputLabel-root": { color: 'black' },
                            "& .MuiOutlinedInput-root": { "& > fieldset": { borderColor: "black" } },
                            "& .MuiOutlinedInput-root.Mui-focused": { "& > fieldset": { borderColor: "black" } },
                            "& .MuiOutlinedInput-root:hover": { "& > fieldset": { borderColor: "black" } },
                            width: 250
                        }}
                        onChange={onChange}
                    />
                </Grid>
                <Grid item xs={12} style={{ marginTop: 10 }}>
                    <TextField
                        id="email"
                        label="Email"
                        value={email}
                        variant="outlined"
                        sx={{
                            "& .MuiInputLabel-root": { color: 'black' },
                            "& .MuiOutlinedInput-root": { "& > fieldset": { borderColor: "black" } },
                            "& .MuiOutlinedInput-root.Mui-focused": { "& > fieldset": { borderColor: "black" } },
                            "& .MuiOutlinedInput-root:hover": { "& > fieldset": { borderColor: "black" } },
                            width: 250
                        }}
                        onChange={onChange}
                    />
                </Grid>
                <Grid item xs={12} style={{ marginTop: 10 }}>
                    <TextField
                        id="password"
                        label="Password"
                        type="password"
                        value={password}
                        variant="outlined"
                        sx={{
                            "& .MuiInputLabel-root": { color: 'black' },
                            "& .MuiOutlinedInput-root": { "& > fieldset": { borderColor: "black" } },
                            "& .MuiOutlinedInput-root.Mui-focused": { "& > fieldset": { borderColor: "black" } },
                            "& .MuiOutlinedInput-root:hover": { "& > fieldset": { borderColor: "black" } },
                            width: 250
                        }}
                        onChange={onChange}
                    />
                </Grid>
                <Grid item xs={12} style={{ marginTop: 40 }}>
                    <Button
                        variant="contained"
                        style={{ width: 250, color: "white", height: 40 }}
                        onClick={onClickSignUp}
                    >
                        <Typography variant="subtitle1">
                            가입
                        </Typography>
                    </Button>
                </Grid>
                <Grid item xs={12} style={{ marginTop: 20 }}>
                    <Typography variant="subtitle2">
                        계정이 있으신가요? <a href="/" style={{ color: "#4e4dec", textDecoration: "none" }}>로그인</a>
                    </Typography>
                </Grid>
            </Grid>
        </Box>
    )
}

export default SignUp;

유저가 이름, 이메일, 비밀번호를 입력하고 가입 버튼을 누르면 Firebase Authentication에서 유효성 검사(이메일 형식, 중복 이메일)를 먼저하고 Firebase Firestore에 id, 이름, 이메일, 대표 이미지(추후에 기본 이미지 추가)를 저장한다. 이 과정이 처리되는 동안 유저는 로딩화면을 보고 있을 것이고 비동기 처리에 대한 결과(성공, 실패)를 alert 형식으로 알 수 있다. 회원가입이 완료되면 "/home"으로 이동되며 서비스를 이용할 수 있다.

 

-Firebase Authentication

 

 

-Firebase Firestore

 

'React.js > SNS Project' 카테고리의 다른 글

Day 6  (0) 2022.08.25
Day 5  (0) 2022.08.24
Day 4  (0) 2022.08.23
Day 2  (0) 2022.08.21
Day 1  (0) 2022.08.20

댓글