<firebase 실시간 데이터베이스와 fullcalendar활용한 일정관리 - index.js>
import React from "react";
import ReactDOM from "react-dom/client";
import "bootstrap/dist/css/bootstrap.min.css";
import "react-datetime/css/react-datetime.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
import ImageUploader from "./service/imageUploader";
import { Provider } from "react-redux";
import { legacy_createStore } from "redux";
import rootReducer from "./redux/rootReducer";
import AuthLogic from "./service/authLogic";
import firebaseApp from "./service/firebase";
import { setAuth } from "./redux/userAuth/action";
// 리덕스 적용하기
const store = legacy_createStore(rootReducer)
// AuthLogic객체 생성하기
const authLogic = new AuthLogic(firebaseApp)
// store에 있는 초기 상태정보 출력하기
store.dispatch(setAuth(authLogic.getUserAuth(), authLogic.getGoogleAuthProvider()))
console.log(store.getState());
// 이미지 업로더 객체 생성
const imageUploader = new ImageUploader();
const root = ReactDOM.createRoot(document.getElementById("root"));
// 리덕스 추가 - store 생성
// createStore 호출
root.render(
<>
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
</>
);
<firebase 실시간 데이터베이스와 fullcalendar활용한 일정관리 - App.jsx>
import { Route, Routes } from "react-router";
import "./App.css";
import HomePage from "./components/page/HomePage";
import MemoPage from "./components/page/MemoPage";
import SchedulePage from "./components/page/SchedulePage";
import MemoDetail from "./components/memo/MemoDetail";
function App() {
return (
<>
<Routes>
<Route path='/' exact={true} element={<HomePage />} />
<Route path='/schedule' exact={true} element={<SchedulePage />} />
<Route path='/memo' exact={true} element={<MemoPage />} />
<Route path='/memo/detail/:m_no' element={<MemoDetail />} />
</Routes>
</>
);
}
export default App;
<firebase 실시간 데이터베이스와 fullcalendar활용한 일정관리 - ScheduleHeader.jsx>
import React from 'react'
import { Container, Nav, Navbar } from 'react-bootstrap'
import { Link } from 'react-router-dom'
const ScheduleHeader = () => {
return (
<>
<Navbar bg="light" variant="light">
<Container fluid>
<Link to="/" className='nav-link'>다이어리</Link>
<Nav className="me-auto">
<Link to="/" className='nav-link'>Home</Link>
<Link to="/schedule" className='nav-link'>일정관리</Link>
<Link to="/memo" className='nav-link'>메모관리</Link>
</Nav>
</Container>
</Navbar>
</>
)
}
export default ScheduleHeader
<firebase 실시간 데이터베이스와 fullcalendar활용한 일정관리 - HomePage.jsx>
import React from 'react'
import ScheduleHeader from '../include/ScheduleHeader'
import ScheduleFooter from '../include/ScheduleFooter'
import { ContainerDiv, FormDiv, HeaderDiv } from '../style/FormStyle'
const HomePage = () => {
return (
<>
<ContainerDiv>
<ScheduleHeader />
<HeaderDiv>
<h1 style={{marginLeft:"10px"}}>다이어리</h1>
</HeaderDiv>
<FormDiv>
<div>이벤트존</div>
<hr style={{height:"2px"}} />
<div>추천 수업존</div>
<hr style={{height:"2px"}} />
<div>지도 화면</div>
<div>카카오맵존</div>
<hr style={{height:"2px"}} />
</FormDiv>
<ScheduleFooter />
</ContainerDiv>
</>
)
}
export default HomePage
<firebase 실시간 데이터베이스와 fullcalendar활용한 일정관리 - SchedulePage.jsx>
import React, { useEffect, useState } from 'react'
import FullCalendar from '@fullcalendar/react'
import dayGridPlugin from '@fullcalendar/daygrid'
import interactionPlugin from '@fullcalendar/interaction'
import ScheduleHeader from '../include/ScheduleHeader'
import axios from 'axios'
import Datetime from 'react-datetime'
import moment from 'moment/moment'
import { Button, Form, Modal } from 'react-bootstrap'
const SchedulePage = () => {
const[memoList, setMemoList] = useState([])
// 오늘 이전 날짜 비활성화 처리하기
const yesterday = moment().subtract(1, 'day')
const valid = (current) => {
return current.isAfter(yesterday)
}
const [show, setShow] = useState(false) // 모달창 초기값
const handleClose = () => setShow(false) // 모달창 닫기
const handleShow = () => setShow(true) // 모달창 보여주기
useEffect(() => {
axios.get('/schedule.json').then(res => {
console.log(res.data)
setMemoList(res.data)
})
}, [])
const handleDateClick = (arg) => {
console.log(arg.dateStr)
handleShow()
}
const handleChangeForm = () => {
}
const memoAdd = () => {
}
const handleStart = (date) => {
console.log('handleStart=> ' + date)
const start = moment(date._d).format('YYYY-MM-DD, a h:mm')
console.log(start)
}
const handleEnd = (date) => {
console.log('handleEnd=> ' + date)
const end = moment(date._d).format('YYYY-MM-DD, a h:mm')
console.log(end)
}
return (
<>
<ScheduleHeader />
<FullCalendar
plugins={[ dayGridPlugin, interactionPlugin ]}
initialView="dayGridMonth"
weekends={true}
events={memoList}
height={"100vh"}
dateClick={handleDateClick}
/>
{/* ========================== [[ 일정등록 Modal ]] ========================== */}
<Modal show={show} onHide={handleClose} animation={true}>
<Modal.Header closeButton>
<Modal.Title>새로운 일정</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form id="f_memo">
<Form.Group className="mb-3 row" controlId="mTitle">
<Form.Label className="col-sm-2 col-form-label">일정명</Form.Label>
<div className='col-sm-10'>
<Form.Control className='form-control form-control-sm' type="text" name="m_title" onChange={handleChangeForm} placeholder="Enter 일정명" />
</div>
</Form.Group>
<Form.Group className="mb-3 row" controlId="boardWriter">
<Form.Label className="col-sm-2 col-form-label">등록자</Form.Label>
<div className='col-sm-10'>
<Form.Control type="text" name="m_writer" onChange={handleChangeForm} className='form-control form-control-sm' placeholder="Enter 작성자" />
</div>
</Form.Group>
<Form.Group className="mb-3 row" controlId="edit-start">
<Form.Label className="col-sm-2 col-form-label">시작</Form.Label>
<div className='col-sm-10'>
<Datetime dateFormat='YYYY-MM-DD' isValidDate={valid} name="m_start" onChange={handleStart} />
</div>
</Form.Group>
<Form.Group className="mb-3 row" controlId="edit-end">
<Form.Label className="col-sm-2 col-form-label">끝</Form.Label>
<div className='col-sm-10'>
<Datetime dateFormat='YYYY-MM-DD' isValidDate={valid} name="m_end" onChange={handleEnd}/>
</div>
</Form.Group>
<Form.Group className="mb-3 row" controlId="boardContent">
<Form.Label className="col-sm-2 col-form-label">내용</Form.Label>
<div className='col-sm-10'>
<textarea className="form-control" name='m_content' onChange={handleChangeForm} rows="3"></textarea>
</div>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
닫기
</Button>
<Button variant="primary" onClick={memoAdd}>
저장
</Button>
</Modal.Footer>
</Modal>
{/* ========================== [[ 글등록 Modal ]] ========================== */}
</>
)
}
export default SchedulePage
<firebase 실시간 데이터베이스와 fullcalendar활용한 일정관리 - MemoPage.jsx>
import React from 'react'
import ScheduleHeader from '../include/ScheduleHeader'
import ScheduleFooter from '../include/ScheduleFooter'
import MemoList from '../memo/MemoList'
const MemoPage = () => {
return (
<div>
<ScheduleHeader />
<MemoList />
<ScheduleFooter />
</div>
)
}
export default MemoPage
<firebase 실시간 데이터베이스와 fullcalendar활용한 일정관리 - MemoList.jsx>
import React, { useEffect, useState } from 'react'
import { Button, Form, Modal, Table } from 'react-bootstrap'
import Datetime from 'react-datetime'
import moment from 'moment/moment'
import '../css/style.css'
import { off, onValue, ref, set } from 'firebase/database'
import { database } from '../../service/firebase'
import MemoRow from './MemoRow'
const MemoList = () => {
// 오늘 이전 날짜 비활성화 처리하기
const yesterday = moment().subtract(1, 'day')
const valid = (current) => {
return current.isAfter(yesterday)
}
const [show, setShow] = useState(false) // 모달창 초기값
const handleClose = () => setShow(false) // 모달창 닫기
const handleShow = () => setShow(true) // 모달창 보여주기
// 사용자로부터 입력받은 값 - 상태훅으로 관리하기
const [m_no, setM_no] = useState(0) // 식별자
const [m_title, setM_title] = useState('') // 일정명
const [m_writer, setM_writer] = useState('') // 작성자
const [m_content, setM_content] = useState('') // 일정내용
const [m_start, setM_start] = useState('') // 시작날짜
const [m_end, setM_end] = useState('') // 끝날짜
const [memo, setMemo] = useState({
m_no: 0,
m_title: '',
m_writer: '',
m_content: '',
m_start: '',
m_end: '',
})
const handleStart = (date) => {
console.log('handleStart=> ' + date)
const m_start = moment(date._d).format('YYYY-MM-DD, a h:mm')
console.log(m_start)
setM_start(m_start)
}
const handleEnd = (date) => {
console.log('handleEnd=> ' + date)
const m_end = moment(date._d).format('YYYY-MM-DD, a h:mm')
console.log(m_end)
setM_end(m_end)
}
// 화면에 입력받은 정보 담기
const handleChangeForm = (event) => {
if(event.currentTarget == null) {
return
}
// console.log('폼내용 변경 발생 name: ' + event.target.name)
// console.log('폼내용 변경 발생 value: ' + event.target.value)
console.log(memo)
setMemo({
...memo,
m_no: Date.now(), // 십진수 날짜 정보
[event.target.name]: event.target.value,
})
console.log(memo)
}
const memoAdd = (event) => {
// 이벤트 버블링 사전처리
event.preventDefault()
console.log(memo)
const pmemo = {
m_no: memo.m_no,
m_title: memo.m_title,
m_writer: memo.m_writer,
m_content: memo.m_content,
m_start: m_start,
m_end: m_end,
}
console.log(pmemo)
set(ref(database, 'memo/' + memo.m_no), pmemo)
handleClose()
}
// 메모 정보 가져오기
const [memos, setMemos] = useState({})
useEffect (() => {
const startCountRef = ref(database, 'memo')
onValue(startCountRef, (snapshot) => {
const data = snapshot.val()
setMemos(data)
console.log(memos)
return () => off(startCountRef)
})
}, [])
const memoSearch = () => {
}
const getMemoList = () => {
}
return (
<>
<div className="container">
<div className="page-header">
<h2>
일정관리 <small>일정목록</small>
</h2>
<hr />
</div>
<div className="row">
<div className="col-3">
<select id="gubun" className="form-select" aria-label="분류선택">
<option defaultValue>분류선택</option>
<option value="m_title">일정명</option>
<option value="m_writer">작성자</option>
<option value="m_content">내용</option>
</select>
</div>
<div className="col-6">
<input
type="text"
id="keyword"
className="form-control"
placeholder="검색어를 입력하세요"
aria-label="검색어를 입력하세요"
aria-describedby="btn_search"
/>
</div>
<div className="col-3">
<Button variant="danger" id="btn_search" onClick={memoSearch}>
검색
</Button>
</div>
</div>
<div className="book-list">
<Table striped bordered hover>
<thead>
<tr>
<th>#</th>
<th>일정명</th>
<th>작성자</th>
<th>일정시간</th>
</tr>
</thead>
<tbody>
{memos && Object.keys(memos).map((key) => (
<MemoRow key={key} memo={memos[key]} />
))}
</tbody>
</Table>
<hr />
<div className="booklist-footer">
<Button variant="warning" onClick={getMemoList}>
전체조회
</Button>
<Button variant="success" onClick={handleShow}>
글쓰기
</Button>
</div>
</div>
</div>
{/* ========================== [[ 일정등록 Modal ]] ========================== */}
<Modal show={show} onHide={handleClose} animation={true}>
<Modal.Header closeButton>
<Modal.Title>새로운 일정</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form id="f_memo">
<Form.Group className="mb-3 row" controlId="mTitle">
<Form.Label className="col-sm-2 col-form-label">일정명</Form.Label>
<div className='col-sm-10'>
<Form.Control className='form-control form-control-sm' type="text" name="m_title" onChange={handleChangeForm} placeholder="Enter 일정명" />
</div>
</Form.Group>
<Form.Group className="mb-3 row" controlId="boardWriter">
<Form.Label className="col-sm-2 col-form-label">등록자</Form.Label>
<div className='col-sm-10'>
<Form.Control type="text" name="m_writer" onChange={handleChangeForm} className='form-control form-control-sm' placeholder="Enter 작성자" />
</div>
</Form.Group>
<Form.Group className="mb-3 row" controlId="edit-start">
<Form.Label className="col-sm-2 col-form-label">시작</Form.Label>
<div className='col-sm-10'>
<Datetime dateFormat='YYYY-MM-DD' isValidDate={valid} name="m_start" onChange={handleStart} />
</div>
</Form.Group>
<Form.Group className="mb-3 row" controlId="edit-end">
<Form.Label className="col-sm-2 col-form-label">끝</Form.Label>
<div className='col-sm-10'>
<Datetime dateFormat='YYYY-MM-DD' isValidDate={valid} name="m_end" onChange={handleEnd}/>
</div>
</Form.Group>
<Form.Group className="mb-3 row" controlId="boardContent">
<Form.Label className="col-sm-2 col-form-label">내용</Form.Label>
<div className='col-sm-10'>
<textarea className="form-control" name='m_content' onChange={handleChangeForm} rows="3"></textarea>
</div>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
닫기
</Button>
<Button variant="primary" onClick={memoAdd}>
저장
</Button>
</Modal.Footer>
</Modal>
{/* ========================== [[ 글등록 Modal ]] ========================== */}
</>
)
}
export default MemoList
<firebase 실시간 데이터베이스와 fullcalendar활용한 일정관리 - MemoRow.jsx>
import React from 'react'
import { Link } from 'react-router-dom'
const MemoRow = ({memo}) => {
return (
<>
<tr>
<td>{memo.m_no}</td>
<td>
<Link to={'/memo/detail/'+memo.m_no} className='btn btn-primary'>
{memo.m_title}
</Link>
</td>
<td>{memo.m_writer}</td>
<td>{`${memo.m_start} ~ ${memo.m_end}`}</td>
</tr>
</>
)
}
export default MemoRow
<firebase 실시간 데이터베이스와 fullcalendar활용한 일정관리 - MemoDetail.jsx>
import React, { useEffect, useState } from 'react'
import { Button, Card, Form, ListGroup, ListGroupItem, Modal } from 'react-bootstrap';
import { useNavigate, useParams } from 'react-router';
import { Link } from 'react-router-dom';
import Datetime from 'react-datetime'
import moment from 'moment/moment';
import { off, onValue, ref, remove, set } from 'firebase/database';
import { database } from '../../service/firebase';
const MemoDetail = () => {
const navigate = useNavigate()
// 사용자가 선택한 로우 m_no
const {m_no} = useParams()
console.log("m_no => " + m_no);
const [memo, setMemo] = useState({})
// 오늘 이전 날짜 비활성화 처리하기
const yesterday = moment().subtract(1, 'day')
const valid = (current) => {
return current.isAfter(yesterday)
}
const [show, setShow] = useState(false) // 모달창 초기값
const handleClose = () => setShow(false) // 모달창 닫기
const handleShow = () => setShow(true) // 모달창 보여주기
// 사용자로부터 입력받은 값 - 상태훅으로 관리하기
const [m_title, setM_title] = useState('') // 일정명
const [m_writer, setM_writer] = useState('') // 작성자
const [m_content, setM_content] = useState('') // 일정내용
const [m_start, setM_start] = useState('') // 시작날짜
const [m_end, setM_end] = useState('') // 끝날짜
useEffect(() => {
const startCountRef = ref(database, 'memo/'+m_no)
onValue(startCountRef, (snapshot) => {
const data = snapshot.val()
setMemo(data)
console.log(memo)
return () => off(startCountRef)
})
}, [])
const memoUpdate = (event) => {
event.preventDefault()
const pmemo = {
m_no: m_no,
m_title: memo.m_title,
m_writer: memo.m_writer,
m_content: memo.m_content,
m_start: m_start ? m_start : memo.m_start,
m_end: m_end ? m_end : memo.m_end,
}
console.log(pmemo)
set(ref(database, 'memo/'+m_no), pmemo)
handleClose()
navigate('/memo')
}
const memoDelete = (event) => {
event.preventDefault()
remove(ref(database, 'memo/'+m_no))
navigate('/memo')
}
const handleStart = (date) => {
console.log('handleStart=> ' + date)
const m_start = moment(date._d).format('YYYY-MM-DD, a h:mm')
console.log(m_start)
setM_start(m_start)
}
const handleEnd = (date) => {
console.log('handleEnd=> ' + date)
const m_end = moment(date._d).format('YYYY-MM-DD, a h:mm')
console.log(m_end)
setM_end(m_end)
}
// 화면에 입력받은 정보 담기
const handleChangeForm = (event) => {
if(event.currentTarget == null) {
return
}
// console.log('폼내용 변경 발생 name: ' + event.target.name)
// console.log('폼내용 변경 발생 value: ' + event.target.value)
console.log(memo)
setMemo({
...memo,
m_no: Date.now(), // 십진수 날짜 정보
[event.target.name]: event.target.value,
})
console.log(memo)
}
return (
<>
<div className="container">
<div className="page-header">
<h2>
일정관리 <small>일정보기</small>
</h2>
<hr />
</div>
<Card style={{ width: "58rem" }}>
<Card.Header>{memo.m_title}</Card.Header>
<ListGroup className="list-group-flush">
<ListGroupItem>{memo.m_writer}</ListGroupItem>
<ListGroupItem>{`${memo.m_start} ~ ${memo.m_end}`}</ListGroupItem>
<ListGroupItem>{memo.m_content}</ListGroupItem>
</ListGroup>
<div className="detail-link">
<Button variant="primary" onClick={handleShow}>
수정
</Button>
<Button variant="primary" onClick={memoDelete}>
삭제
</Button>
<Link to="/memo" className="nav-link">
일정목록
</Link>
</div>
</Card>
<hr />
{/* ========================== [[ 일정등록 Modal ]] ========================== */}
<Modal show={show} onHide={handleClose} animation={true}>
<Modal.Header closeButton>
<Modal.Title>일정 수정</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form id="f_memo">
<Form.Group className="mb-3 row" controlId="mTitle">
<Form.Label className="col-sm-2 col-form-label">
일정명
</Form.Label>
<div className="col-sm-10">
<Form.Control
className="form-control form-control-sm"
type="text"
name="m_title"
value={memo.m_title}
onChange={handleChangeForm}
placeholder="Enter 일정명"
/>
</div>
</Form.Group>
<Form.Group className="mb-3 row" controlId="boardWriter">
<Form.Label className="col-sm-2 col-form-label">
등록자
</Form.Label>
<div className="col-sm-10">
<Form.Control
type="text"
name="m_writer"
value={memo.m_writer}
onChange={handleChangeForm}
className="form-control form-control-sm"
placeholder="Enter 작성자"
/>
</div>
</Form.Group>
<Form.Group className="mb-3 row" controlId="edit-start">
<Form.Label className="col-sm-2 col-form-label">
시작
</Form.Label>
<div className="col-sm-10">
<Datetime
dateFormat="YYYY-MM-DD"
isValidDate={valid}
name="m_start"
value={memo.m_start}
onChange={handleStart}
/>
</div>
</Form.Group>
<Form.Group className="mb-3 row" controlId="edit-end">
<Form.Label className="col-sm-2 col-form-label">끝</Form.Label>
<div className="col-sm-10">
<Datetime
dateFormat="YYYY-MM-DD"
isValidDate={valid}
name="m_end"
value={memo.m_end}
onChange={handleEnd}
/>
</div>
</Form.Group>
<Form.Group className="mb-3 row" controlId="boardContent">
<Form.Label className="col-sm-2 col-form-label">
내용
</Form.Label>
<div className="col-sm-10">
<textarea
className="form-control"
name="m_content"
value={memo.m_content}
onChange={handleChangeForm}
rows="3"
></textarea>
</div>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
닫기
</Button>
<Button variant="primary" onClick={memoUpdate}>
저장
</Button>
</Modal.Footer>
</Modal>
{/* ========================== [[ 글등록 Modal ]] ========================== */}
</div>
</>
)
}
export default MemoDetail
<firebase 실시간 데이터베이스와 fullcalendar활용한 일정관리 - firebase.js>
import { initializeApp } from "firebase/app";
import { getDatabase } from "firebase/database";
const firebaseConfig = {
apiKey: process.env.REACT_APP_FS_APIKEY,
authDomain: process.env.REACT_APP_FS_AUTHDOMAIN,
databaseURL: process.env.REACT_APP_FS_DATABASEURL,
projectId: process.env.REACT_APP_FS_PROJECTID,
storageBucket: process.env.REACT_APP_FS_STORAGEBUCKET,
messagingSenderId: process.env.REACT_APP_FS_MESSAGINGSENDERID,
appId: process.env.REACT_APP_FS_APPID,
};
const firebaseApp = initializeApp(firebaseConfig);
export default firebaseApp;
export const database = getDatabase(firebaseApp);
'국비학원 > 수업기록' 카테고리의 다른 글
국비 지원 개발자 과정_Day99 (0) | 2023.04.20 |
---|---|
국비 지원 개발자 과정_Day98 (0) | 2023.04.19 |
국비 지원 개발자 과정_Day96 (0) | 2023.04.17 |
국비 지원 개발자 과정_Day95 (0) | 2023.04.14 |
국비 지원 개발자 과정_Day94 (0) | 2023.04.13 |
댓글