본문 바로가기
국비학원/수업기록

국비 지원 개발자 과정_Day91

by 루팽 2023. 4. 7.

components

  include

  page

  login

 

service

  firebase / authLogic

 

redux

  toast

  userAuth

 

App.jsx

  / → Login.jsx

  /maker → Market.jsx

 

<네임카드 작성 - App.jsx>

import { Route, Routes } from "react-router-dom";
import "./App.css";
import styled from "styled-components";
import Login from "./components/login/Login";
import CardManager from "./components/page/CardManager";

const AppDiv = styled.div`
  width: 100%;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-item: center;
  background-color: #FFF3E2;
`

const App = () => {
  return (
    <>
      <AppDiv>
        <Routes>
          <Route path="/" element={<Login />} />
          <Route path="/manager" element={<CardManager />} />
        </Routes>
      </AppDiv>
    </>
  );
}

export default App;

 

<네임카드 작성 - Login.jsx>

import React, { useState } from 'react'
import styled from 'styled-components'
import Header from '../include/Header'
import Footer from '../include/Footer'
import { useNavigate } from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'
import { setToastMsg } from '../../redux/toastStatus/action'
import { loginGoogle } from '../../service/authLogic'

const LoginDiv = styled.div`
  width: 30em;
  background-color: white;
  text-align: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
`

const ListUl = styled.ul`
  width: 100%;
  display: flex;
  flex-direction: column;
  padding: 0.5rem;
  list-style: none;
`

const ItemLi = styled.li`
  margin-bottom: 0.5em;
`

const BtnLogin = styled.button`
  width: 100%;
  height: 2.5em;
  font-size: 1.2rem;
  border-radius: 1.2rem;
  background-color: transparent;
  color: #E74646;
  cursor: pointer;
  border: 0.2rem solid #FA9884;
  outline: 0;
  &:hover{
  background-color: #FA9884;
  color: #FFF3E2;
  }
`

const Login = () => {
  // 구글 로그인 성공시 CardManager화면으로 이동처리에 사용
  const navigate = useNavigate()
  // 구글 로그인 진행 중 에러 발생하면 에러 메시지 출력 처리 위해 사용
  const dispatch = useDispatch()
  // 구글 로그인시 auth와 googleProvider 파라미터로 전송위해
  const userAuth = useSelector(store => store.userAuth)
  const [userId, setUserId] = useState()
  const onLogin = async() => {
    try {
      const result = await loginGoogle(userAuth.auth, userAuth.googleProvider)
      console.log(result)
      console.log(result.uid)
      setUserId(result.uid)
      window.localStorage.setItem("userId", result.uid)
      navigate('/manager')
      // window.location.reload()
    } catch (error) {
      dispatch(setToastMsg(error+': 로그인 오류'))
    }
  }

  return (
    <LoginDiv>
      <Header />
      <section>
        <h1>Login</h1>
      <ListUl>
        <ItemLi><BtnLogin onClick={onLogin}>Google</BtnLogin></ItemLi>
        <ItemLi><BtnLogin>Github</BtnLogin></ItemLi>
      </ListUl>
      </section>
      <Footer />
    </LoginDiv>
  )
}

export default Login

 

<네임카드 작성 - Header.jsx>

import React, { useEffect, useState } from 'react'
import { useSelector } from 'react-redux'
import { useNavigate } from 'react-router-dom'
import styled from 'styled-components'
import { logout } from '../../service/authLogic'

const HeaderDiv = styled.div`
  width: 100%;
  text-align: center;
  background-color: #FFE5CA;
  padding: 0.5em;
  position: relative;
`

const Img = styled.img`
  width: 3em;
`

const BtnLogout = styled.button`
  position: absolute;
  right: 3em;
  top: 1em;
  padding: 0.8em;
  border-radius: 20%;
  background-color: #FA9884;
  color: #FFF3E2;
  outline: 0;
  border: 0;
  cursor: pointer;
`

const TitleH1 = styled.h1`
  color: #E74646;
`

const Header = () => {
  const navigate = useNavigate()
  const {userAuth} = useSelector(state => state)
  const [userId, setUserId] = useState()
  useEffect(() => {
    setUserId(localStorage.getItem("userId"))
  }, [])

  const onLogout = () => {
    console.log('onLogout')
    logout(userAuth.auth)
    navigate('/')
    // window.location.reload()
  }
  return (
    <HeaderDiv>
      {userId && <BtnLogout onClick={onLogout}>Logout</BtnLogout>}
      <Img src='/images/icon-palette.png' alt='logo' />
      <TitleH1>Name Card</TitleH1>
    </HeaderDiv>
  )
}

export default Header

 

<네임카드 작성 - Footer.jsx>

import React from 'react'
import styled from 'styled-components'

const FooterDiv = styled.div`
  width: 100%;
  background-color: #FA9884;
  text-align: center;
`

const TitleP = styled.p`
  color: #FFF3E2;
`

const Footer = () => {
  return (
    <FooterDiv>
      <TitleP>No pain, No gain</TitleP>
    </FooterDiv>
  )
}

export default Footer

 

<네임카드 작성 - CardManager.jsx>

import React, { useState } from 'react'
import Header from '../include/Header'
import Footer from '../include/Footer'
import styled from 'styled-components'
import Preview from './Preview'
import CardEditor from './CardEditor'

const MakerDiv = styled.div`
  width: 100%;
  height: 100%;
  max-width: 80rem;
  display: flex;
  flex-direction: column;
  background-color: white;
`

const ContainerDiv = styled.div`
  display: flex;
  flex: 1;
  min-height: 0;
`

const CardManager = () => {
  const [cards, setCards] = useState({
    '1':{
      id: '1',
      name: '이성계',
      company: 'Samsung',
      theme: 'dark',
      title: 'Software Engineer',
      email: 'lee@gmail.com',
      message: 'go for it',
      fileName: 'lee',
      fileURL: null,
    },
  '2':{
      id: '2',
      name: '김유신',
      company: 'Cupang',
      theme: 'light',
      title: 'Software Engineer',
      email: 'kim@gmail.com',
      message: 'I can do it',
      fileName: 'kim',
      fileURL: 'kim.png',
  },
  '3':{
      id: '3',
      name: '유재석',
      company: 'MBC',
      theme: 'colorful',
      title: 'Software Engineer',
      email: 'you@gmail.com',
      message: 'we are the world',
      fileName: 'you',
      fileURL: null,
  }
});

  return (
    <MakerDiv>
      <Header />
        <ContainerDiv>
          <CardEditor cards={cards} />
          <Preview cards={cards} />
        </ContainerDiv>
      <Footer />
    </MakerDiv>
  )
}

export default CardManager

 

<네임카드 작성 - Preview.jsx>

import React from 'react'
import styled from 'styled-components'
import Card from './Card'

const PreviewDiv = styled.div`
  flex-basis: 50%;
  overflow: auto;
`

const TitleH1 = styled.h1`
  width: 100%;
  text-align: center;
  margin-bottom: 1em;
  color: #E74646;
`

const CardsUl = styled.ul`
  width: 100%;
  height: 100%;
  padding: 0.5em 2em;
  display: flex;
  flex-direction: column;
  align-item: center;
`

const Preview = ({cards}) => {
  return (
    <PreviewDiv>
      <TitleH1>
        CardPreview
      </TitleH1>
      <CardsUl>
        {
          Object.keys(cards).map((key) => (
            <Card key={key} card={cards[key]} />
          ))
        }
      </CardsUl>
    </PreviewDiv>
  )
}

export default Preview

 

<네임카드 작성 - Card.jsx>

import React from 'react'
import styled from 'styled-components'
import styles from './card.module.css'

const CardLi = styled.li`
  display: flex; /* 이름같은것들 이미지 옆으로 보내기 */
  align-items: center; /* flex속성일때 사용 가능 */
  width: 100%;
  background-color: #FFE5CA;
  margin-bottom: 0.5em;
  border-radius: 1em;
  padding: 0.2em 0;
  box-shadow: 6px 6px 8px 0px rgba(217,217,217,1);
  max-width: 30em; /* 넓이 제약 */
`

const AvatarImg = styled.img`
  width: 10em;
  height: 10em;
  padding: 1em;
  border-radius:20%
  margin-right: 1em; /* 이미지와 글자사이에 마진 */
  margin-left: 0.5em; /* 이미지 앞쪽에 마진 */
`

const NameH1 = styled.h1`
  margin: 0;
  font-size: 1.2rem;
  margin-bottom: 0.2em;
`

const CompanyP = styled.p`
  margin: 0;
  font-size: 0.8rem;
  margin-bottom: 1em;
`

const TitleP = styled.p`
  margin: 0;
  font-size: 0.8rem;
  margin-bottom: 1em;
`

const EmailP = styled.p`
  margin: 0;
  font-size: 0.8rem;
  margin-bottom: 1em;
`
const MessageP = styled.p`
  margin: 0;
  font-size: 0.8rem;
  margin-bottom: 1em;
`

const Card = ({card}) => {
  const DEFAULT_IMG = '/images/icon-coin.png'
  const {name, company, title, email, message, theme } = card
  const getStyles = (theme) => {
    switch(theme) {
      case 'dark':
        return styles.dark;
      case 'light':
        return styles.light;
      case 'colorful':
        return styles.colorful;
      default:
        throw new Error(`unknown theme:${theme}`)
    }
  }
  return (
    <CardLi className={`${styles.card} ${getStyles(theme)}`}>
      <AvatarImg src={DEFAULT_IMG} alt='profile image' />
      <div className={{width: '100%'}}>
        <NameH1>{name}</NameH1>
        <CompanyP>{company}</CompanyP>
        <TitleP>{title}</TitleP>
        <EmailP>{email}</EmailP>
        <MessageP>{message}</MessageP>
      </div>
    </CardLi>
  )
}

export default Card

 

.<네임카드 작성 - CardEditor.jsx>

import React from 'react'
import CardEditorForm from './CardEditorForm'
import CardAddForm from './CardAddForm'
import styled from 'styled-components'

const EditorDiv = styled.div`
  flex-basis: 50%;
  border-right: 2px solid #FFE5CA;
  padding: 0.5em 2em;
  overflow-y: auto;
`

const TitleH1 = styled.h1`
  width: 100%;
  text-align: center;
  margin-bottom: 1em;
  color: #E74646;
`

const CardEditor = ({cards}) => {
  return (
    <EditorDiv>
      <TitleH1>Card Editor</TitleH1>
      {Object.keys(cards).map(key => (
        <CardEditorForm key={key} />
      ))
      }
      <CardAddForm />
    </EditorDiv>
  )
}

export default CardEditor

댓글