노력이 좋아서

<step75>'react_고객관리 사이트 구현_step1'

zoaseo 2022. 7. 7. 09:57

1) 

고객관리

green_customer_client

Header

Footer

CustomerList

Customer

DetailCustomer

 

라이브러리

axios 

react-router-dom

material-ui

https://mui.com/material-ui/getting-started/overview/

 

Material UI - Overview - Material UI

Material UI is a library of React UI components that implements Google's Material Design.

mui.com

고객관리서버

api 서버

node.js

express

 

데이터베이스 AWS

https://blog.naver.com/pink_candy02/222624278720

 

AWS RDS 서비스를 이용하여 MySQL DB 구축하기

https://aws.amazon.com/ko/ 회원가입하기 1) 이메일 주소, 암호, AWS 계정 이름을 선택 후 계속(1/5단...

blog.naver.com

2)

green_customer_client

npm install @mui/material @emotion/react @emotion/styled
npm install router-react-dom@6
npm install axios
npm install react-daum-postcode
npm install react-dom

components/

CreateCustomer.js

import React, { useState } from 'react';
import { Table, TableBody, TableRow, TableCell } from '@mui/material';
import PopupDom from './PopupDom';
import PopupPostCode from './PopupPostCode';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
const CreateCustomer = () => {
    const navigate = useNavigate(); // 리다이렉션
    // 우편번호 관리하기
    const onAddData = (data) => {
        console.log(data);
        setFormData({
            ...formData,
            c_add: data.address,
        })
    }
    // 팝업창 상태 관리
    const [ isPopupOpen, setIsPopupOpen] = useState(false);
    // 팝업창 상태 true로 변경
    const openPostCode = () => {
        setIsPopupOpen(true);
    }
    // 팝업창 상태 false로 변경
    const closePostCode = () => {
        setIsPopupOpen(false);
    }
    const [ formData, setFormData ] = useState({
        c_name: "",
        c_phone: "",
        c_birth: "",
        c_gender: "",
        c_add: "",
        c_adddetail: "",
    })
    const onChange = (e) => {
        const { name, value } = e.target;
        setFormData({
            ...formData,
            [name]: value
        })
    }
    // 폼 submit 이벤트
    const onSubmit = (e) => {
        // form에 원래 연결된 이벤트를 제거
        e.preventDefault();
        console.log(formData);
        // input에 값이 있는지 체크하고
        // 입력이 다되어있으면 post전송
        insertCustomer();
    }
    function insertCustomer(){
        axios.post("http://localhost:3001/customers",formData)
        .then((result)=>{
            console.log(result);
            navigate("/"); // 리다이렉션 추가
        })
        .catch(e=>{
            console.log(e);
        })
    }
    return (
        <div>
            <h2>신규 고객 등록하기</h2>
            <form onSubmit={onSubmit}>
                <Table>
                    <TableBody>
                        <TableRow>
                            <TableCell>이름</TableCell>
                            <TableCell>
                                <input name="c_name" type="text" 
                                value={formData.c_name}
                                onChange={onChange}/>
                            </TableCell>
                        </TableRow>
                        <TableRow>
                            <TableCell>연락처</TableCell>
                            <TableCell>
                                <input name="c_phone" type="text" 
                                value={formData.c_phone}
                                onChange={onChange}/>
                            </TableCell>
                        </TableRow>
                        <TableRow>
                            <TableCell>생년월일</TableCell>
                            <TableCell>
                                <input name="c_birth" type="date" 
                                value={formData.c_birth}
                                onChange={onChange}/>
                            </TableCell>
                        </TableRow>
                        <TableRow>
                            <TableCell>성별</TableCell>
                            <TableCell>
                                여성<input name="c_gender" type="radio" 
                                value="여성"
                                onChange={onChange}/>
                                남성<input name="c_gender" type="radio" 
                                value="남성"
                                onChange={onChange}/>
                            </TableCell>
                        </TableRow>
                        <TableRow>
                            <TableCell>주소</TableCell>
                            <TableCell>
                                <input name="c_add" type="text" 
                                value={formData.c_add}
                                onChange={onChange}/>
                                <input name="c_adddetail" type="text"
                                value={formData.c_adddetail}
                                onChange={onChange}/>
                                <button type="button" onClick={openPostCode}>우편번호 검색</button>
                                <div id="popupDom">
                                    {isPopupOpen && (
                                        <PopupDom>
                                            <PopupPostCode onClose={closePostCode}
                                            onAddData={onAddData}/>
                                        </PopupDom>
                                    )}
                                </div>
                            </TableCell>
                        </TableRow>
                        <TableRow>
                            <TableCell colSpan={2}>
                                <button type="submit">등록</button>
                                <button type="reset">취소</button>
                            </TableCell>
                        </TableRow>
                    </TableBody>
                </Table>                
            </form>
        </div>
    );
};

export default CreateCustomer;

Customer.js

import React from 'react';
import { TableRow, TableCell } from '@mui/material';
import { Link } from 'react-router-dom';

const Customer = ({customer}) => {

    return (
        <TableRow>
            <TableCell>{customer.no}</TableCell>
            <TableCell><Link to={`/detailview/${customer.no}`}>{customer.name}</Link></TableCell>
            <TableCell>{customer.phone}</TableCell>
            <TableCell>{customer.birth}</TableCell>
            <TableCell>{customer.gender}</TableCell>
            <TableCell>{customer.add1}</TableCell>
            <TableCell>{customer.add2}</TableCell>
        </TableRow>
    );
};

export default Customer;

CustomerList.js

import React from 'react';
import { Table, TableBody, TableHead, TableCell, TableRow} from '@mui/material';
import Customer from './Customer';
import axios from 'axios';
import useAsync from '../customHook/useAsync';

async function getCustomers(){
    const response = await axios.get("http://localhost:3001/customers");
    return response.data;
}
const CustomerList = () => {
    const [ state ] = useAsync(getCustomers,[]);
    const { loading, data:customers, error } = state;
    if(loading) return <div>로딩중....</div>
    if(error) return <div>에러가 발생했습니다.</div>
    if(!customers) return <div>로딩중입니다.</div>

    return (
        <div>
            <h2>고객리스트</h2>
            <Table>
                <TableHead>
                    <TableRow>
                        <TableCell>번호</TableCell>
                        <TableCell>이름</TableCell>
                        <TableCell>연락처</TableCell>
                        <TableCell>생년월일</TableCell>
                        <TableCell>성별</TableCell>
                        <TableCell>주소</TableCell>
                        <TableCell>상세주소</TableCell>
                    </TableRow>
                </TableHead>
                <TableBody>
                    {customers.map(customer=>(
                        <Customer key={customer.no} customer={customer}/>
                    ))}
                </TableBody>
            </Table>
        </div>
    );
};

export default CustomerList;

DetailCustomer.js

import React from 'react';
import { Table, TableBody, TableCell, TableRow } from '@mui/material';
import axios from 'axios';
import useAsync from '../customHook/useAsync';
import { useParams } from 'react-router-dom';

async function getCustomers(no){
    const response = await axios.get(`http://localhost:3001/detailview/${no}`);
    return response.data;
}   
const DetailCustomer = () => {
    const { no } = useParams();
    const [ state ] = useAsync(()=>getCustomers(no),[no]);
    const { loading, data:customer, error } = state;
    if(loading) return <div>로딩중.....</div>
    if(error) return <div>에러가 발생했습니다.</div>
    if(!customer) return <div>로딩중입니다.</div>
    return (
        <div>
            <h2>고객 상세 정보</h2>
            <Table>
                <TableBody>
                    <TableRow>
                        <TableCell>고객명</TableCell>
                        <TableCell>{customer.name}</TableCell>
                    </TableRow>
                    <TableRow>
                        <TableCell>연락처</TableCell>
                        <TableCell>{customer.phone}</TableCell>
                    </TableRow>
                    <TableRow>
                        <TableCell>생년월일</TableCell>
                        <TableCell>{customer.birth}</TableCell>
                    </TableRow>
                    <TableRow>
                        <TableCell>주소</TableCell>
                        <TableCell>{customer.add1}</TableCell>
                    </TableRow>
                    <TableRow>
                        <TableCell>상세주소</TableCell>
                        <TableCell>{customer.add2}</TableCell>
                    </TableRow>
                </TableBody>
            </Table>
        </div>
    );
};

export default DetailCustomer;

Footer.js

import React from 'react';

const Footer = () => {
    return (
        <div id="footer">
            <h1>그린 고객 관리</h1>
            <p>
                대표자 : 김그린 | 사업자 등록번호 214-86-12345<br/>
                통신판매업 신고 : 강남 13711호 | 학원등록번호 : 강남 제 1104호<br/>
                주소 : 서울시 강남구 역삼동 강남빌딩 5층<br/>
                copyright (c) 2022 gitaAcademy
            </p>
        </div>
    );
};

export default Footer;

Header.js

import React from 'react';
import { Link } from 'react-router-dom';

const Header = () => {
    return (
        <div id="header">
            <h1>그린고객센터</h1>
            <ul>
                <li><Link to="/">고객리스트보기</Link></li>
                <li><Link to="/write">신규 고객 등록하기</Link></li>
                <li>고객 검색</li>
            </ul>
        </div>
    );
};

export default Header;

PopupDom.js

import ReactDom from 'react-dom';

const PopupDom = ({children}) => {
    const el = document.getElementById('popupDom');
    return ReactDom.createPortal(children, el);
};

export default PopupDom;

PopupPostCode.js

import React from 'react';
import DaumPostcode from "react-daum-postcode";
 
const PopupPostCode = (props) => {
	// 우편번호 검색 후 주소 클릭 시 실행될 함수, data callback 용
    const handlePostCode = (data) => {
        let fullAddress = data.address;
        let extraAddress = ''; 
        
        if (data.addressType === 'R') {
          if (data.bname !== '') {
            extraAddress += data.bname;
          }
          if (data.buildingName !== '') {
            extraAddress += (extraAddress !== '' ? `, ${data.buildingName}` : data.buildingName);
          }
          fullAddress += (extraAddress !== '' ? ` (${extraAddress})` : '');
        }
        console.log(data)
        console.log(fullAddress)
        console.log(data.zonecode)
        props.onAddData(data);
        
    }

    const postCodeStyle = {
        display: "block",
        position: "absolute",
        top: '50%',
        left: '50%',
        transform:'translate(-50%,-50%)',
        width: "600px",
        height: "600px",
        padding: "7px",
        border: "2px solid #666"
      };
 
    return(
        <div>
            <DaumPostcode style={postCodeStyle} onComplete={handlePostCode} /> 
            <button type='button' onClick={() => {props.onClose()}} className='postCode_btn'>입력</button>
        </div>
    )
}
 
export default PopupPostCode;

customHook/

useAsync.js

import { useReducer, useEffect } from 'react';
const initialState = {
    loading: false,
    data: null,
    error: null,
}

function reducer(state, action){
    switch(action.type){
        case "LOADING":
            return {
                ...initialState,
                loading: true,
            }
        case "SUCCESS":
            return {
                ...initialState,
                data: action.data,
            }
        case "ERROR":
            return {
                ...initialState,
                error: action.error,
            }
        default:
            return state;
    }
}
function useAsync(callback, deps=[]){
    const [ state, dispatch ] = useReducer(reducer, initialState);
    const fetchDate = async () => {
        dispatch({type: "LOADING"});
        try {
            const data = await callback();
            dispatch({
                type: "SUCCESS",
                data: data,
            })
        }
        catch(e) {
            dispatch({
                type: "ERROR",
                error: e,
            })
        }
    }
    useEffect(()=>{
        fetchDate();
        // eslint-disable-next-line
    },deps);
    return [ state, fetchDate ];
}
export default useAsync;

App.css

li { list-style: none; }
a { text-decoration: none; color: inherit; }
.App {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
}
#header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid #ccc;
  margin-bottom: 50px;
}
#header ul {
  display: flex;
}
#header li {
  padding: 0 20px;
}
h1 {
  font-size: 24px;
}
#footer {
  padding-top: 50px;
}

App.js

import './App.css';
import CustomerList from './components/CustomerList';
import DetailCustomer from './components/DetailCustomer';
import Footer from './components/Footer';
import Header from './components/Header';
import { Route, Routes } from 'react-router-dom';
import CreateCustomer from './components/CreateCustomer';
const customers = [
  {
    no: 1,
    name: "고객",
    phone: "01012345678",
    birth: "19920206",
    gender: "여성",
    add: "울산시 남구",
  },
  {
    no: 2,
    name: "그린",
    phone: "01012345678",
    birth: "19920206",
    gender: "남성",
    add: "울산시 동구",
  },
  {
    no: 3,
    name: "kh",
    phone: "01012345678",
    birth: "19920206",
    gender: "여성",
    add: "울산시 북구",
  },
]
function App() {
  return (
    <div className="App">
      <Header/>
      <Routes>
        <Route path="/" element={<CustomerList customers={customers}/>}/>
        <Route path="/detailview/:no" element={<DetailCustomer/>}/>
        <Route path="/write" element={<CreateCustomer/>}/>
      </Routes>
      <Footer/>
    </div>
  );
}

export default App;

 

green_customer_server

npm init
npm install express
npm install cors
npm install mysql

database.json

{
    "host": "customer-data.cfwxhfzwpudu.ap-northeast-2.rds.amazonaws.com",
    "user": "admin",
    "password": "xxxx",
    "port": "3306",
    "database": "customers"
}

index.js

const express = require("express");
const cors = require("cors");
const app = express();
const port = 3001;
const mysql = require("mysql");
const fs = require("fs");

const dbinfo = fs.readFileSync('./database.json');
// 받아온 json데이터를 객체형태로 변경 JSON.parse
const conf = JSON.parse(dbinfo);

// connection mysql연결 createConnection()
// connection.connect() 연결하기
// connection.end() 연결종료
// connection.query('쿼리문', callback함수)
// callback(error, result, result의 field정보)

const connection = mysql.createConnection({
    host: conf.host,
    user: conf.user,
    password: conf.password,
    port: conf.port,
    database: conf.database,
})
app.use(express.json());
app.use(cors());

app.get('/customers', async (req,res)=>{
    // connection.connect();
    connection.query(
        "select * from customers_table",
        (err, rows, fields)=>{
            res.send(rows);     
        }
    )
    // connection.end();
})

// 서버실행
app.listen(port, ()=>{
    console.log("고객 서버가 돌아가고 있습니다.");
})

app.get('/detailview/:no', async (req,res)=>{
    const params = req.params;
    const { no } = params;
    connection.query(
        `select * from customers_table where no=${no}`,
        (err, rows, fields)=>{
            res.send(rows[0]);
        }
    )
})

app.post('/customers', async (req,res)=>{
    const body = req.body;
    const { c_name, c_phone, c_birth, c_gender, c_add, c_adddetail } = body;
    if(!c_name || !c_phone || !c_birth || !c_gender || !c_add || !c_adddetail) {
        res.send("모든 필드를 입력해주세요");
    }
    connection.query(
        `insert into customers_table (name,phone,birth,gender,add1,add2)
        values (
            '${c_name}','${c_phone}','${c_birth}','${c_gender}','${c_add}','${c_adddetail}')`,
        (err, rows, fields)=>{
            res.send(rows);
        }
    )
})