TransactionForm.jsx생성
import React from "react";
const TransactionForm = () => {
const [name, setName] = useState("");
const [amount, setAmount] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
console.log({
name,
amount,
});
};
return (
<div>
<h3>거래 추가</h3>
<form onSubmit={handleSubmit}>
<label>
<span>거래명:</span>
<input
type="text"
required
onChange={(e) => setName(e.target.value)}
value={name}
/>
</label>
<label>
<span>가격(원):</span>
<input
type="number"
required
onChange={(e) => setAmount(e.target.value)}
value={amount}
/>
</label>
<button>추가</button>
</form>
</div>
);
};
export default TransactionForm;
Home.jsx에 새로 추가한 TransactionForm 컴포넌트 추가
import TransactionForm from "../../Components/TransactionForm";
import styles from "./Home.module.css";
const Home = () => {
return (
<div className={styles.container}>
<div className={styles.content}>거래 내역</div>
<div className={styles.sidebar}>
<TransactionForm />
</div>
</div>
);
};
export default Home;
Home.module.css
.container {
display: grid;
grid-template-columns: 2fr 1fr;
max-width: 960px;
margin: 60px auto;
}
.content {
padding-right: 30px;
}
.sidebar {
padding-left: 30px;
}
.sidebar form {
padding: 20px;
background: #1f9751;
border-radius: 10px;
}
.sidebar input,
.sidebar select {
display: block;
width: 100%;
padding: 10px;
margin-top: 8px;
box-sizing: border-box;
border: 0;
border-radius: 4px;
color: #555;
font-size: 1em;
}
.sidebar label {
margin: 0 auto 20px;
display: block;
color: #fff;
}
.sidebar button {
color: #fff;
border: 2px solid #fff;
padding: 6px 12px;
background-color: transparent;
font-size: 1em;
border-radius: 4px;
cursor: pointer;
display: block;
width: 100%;
}
.sidebar h3 {
color: #1f9751;
margin-bottom: 20px;
}
.sidebar aside {
margin-top: 40px;
color: #555;
}
.sidebar aside li {
margin: 10px;
}
이제 거래내역을 가져올거임
hooks에 useFireStore.js추가
import { useEffect, useReducer, useState } from "react";
import { firedb, timestamp } from "../firebase/config";
//초기상태
let initalState = {
document: null,
isPending: false,
error: null,
success: false,
};
const firestoreReducer = (state, action) => {
switch (action.type) {
case "IS_PENDING":
return { isPending: true, document: null, success: false, errror: null };
case "ADDED_DOCUMENT":
return {
isPending: false,
document: action.payload,
success: true,
errror: null,
};
case "ERROR":
return {
isPending: false,
document: null,
success: false,
errror: action.payload,
};
default:
return state;
}
};
export const useFirestore = (collection) => {
const [response, dispatch] = useReducer(firestoreReducer, initalState);
const [isCancelled, setIsCancelled] = useState(false);
// DB 컬렉션 레퍼런스
const ref = firedb.collection(collection);
// 취소가 아닐경우에만 디스패치하기
const dispatchIfNotCancelled = (action) => {
if (!isCancelled) {
dispatch(action);
}
};
// doc 추가
const addDocument = async (doc) => {
dispatch({ type: "IS_PENDING" });
try {
const createdAt = timestamp.fromDate(new Date());
const addedDocument = await ref.add({ ...doc, createdAt });
dispatchIfNotCancelled({
type: "ADDED_DOCUMENT",
payload: addedDocument,
});
} catch (err) {
dispatchIfNotCancelled({ type: "ERROR", payload: err.message });
}
};
useEffect(() => {
setIsCancelled(false);
return () => setIsCancelled(true);
}, []);
return { addDocument, response };
};
config.js에 시간 추가함 (export에도 추가)
//파이어 스토어 DB서비스
//init service
const firedb = firebase.firestore();
//인증서비스
const fireauth = firebase.auth();
//timestamp 시간
const timestamp = firebase.firestore.Timestamp;
useFireStore.js
// doc 추가
const addDocument = async (doc) => {
dispatch({ type: "IS_PENDING" });
try {
const createdAt = timestamp.fromDate(new Date()); //현재날짜시간으로 날짜데이터 만들기
const addedDocument = await ref.add({ ...doc, createdAt }); //날짜시간과 함께 저장하기
dispatchIfNotCancelled({
type: "ADDED_DOCUMENT",
payload: addedDocument,
});
} catch (err) {
dispatchIfNotCancelled({ type: "ERROR", payload: err.message });
}
};
ADDED_DOCUMENT 를 사용하여 새 거래내역을 추가한다.
TransactionForm.jsx
import React, { useState } from "react";
import { useFirestore } from "../hooks/useFireStore";
const TransactionForm = ({ uid }) => {
const [name, setName] = useState("");
const [amount, setAmount] = useState("");
const [addDocument, response] = useFirestore("transactions"); //파이어스토어에 새로 문서추가 가져오기
const handleSubmit = (e) => {
e.preventDefault();
addDocument({
uid,
name,
amount,
});
};
//db에 새문서 저장후 폼 내용 없애기
useEffect(() => {
if (response.success) {
setName("");
setAmount("");
}
}, [response.success]);
return (
<div>
<h3>거래 추가</h3>
<form onSubmit={handleSubmit}>
<label>
<span>거래명:</span>
<input
type="text"
required
onChange={(e) => setName(e.target.value)}
value={name}
/>
</label>
<label>
<span>가격(원):</span>
<input
type="number"
required
onChange={(e) => setAmount(e.target.value)}
value={amount}
/>
</label>
<button>추가</button>
</form>
</div>
);
};
export default TransactionForm;
오이 2천원 추가해봄
추가는 됐지만 실시간으로 확인을 하고 싶다.
useCollection.js
import { useEffect, useState } from "react";
import { firedb } from "../firebase/config";
export const useCollection = (collection) => {
const [documents, setDocuments] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
let ref = firedb.collection(collection);
const unsub = ref.onSnapshot(
(snapshot) => {
let results = [];
snapshot.docs.forEach((doc) => {
results.push({ ...doc.data(), id: doc.id }); //모든 필드가 추가되고, doc id도 추가
});
setDocuments(results);
setError(null);
},
(err) => {
console.log(err);
setError("데이터를 가져올 수 없습니다.");
}
);
return () => unsub();
}, [collection]);
return { documents, error };
};
Home.jsx
로그인 된 유저의 거래내역만 볼 수 있도록
조건 추가
import TransactionForm from "../../Components/TransactionForm";
import { useAuthContext } from "../../hooks/useAuthContext";
import { useCollection } from "../../hooks/useCollection";
import styles from "./Home.module.css";
import TransactionList from "./TransactionList";
const Home = () => {
const { user } = useAuthContext();
const { documents, error } = useCollection("transactions", [
"uid",
"==",
user.uid,
]);
return (
<div className={styles.container}>
<div className={styles.content}>
{error && <p>{error}</p>}
{documents && <TransactionList transactions={documents} />}
</div>
<div className={styles.sidebar}>
<TransactionForm uid={user.uid} />
</div>
</div>
);
};
export default Home;
TransactionList.jsx
import styles from "./Home.module.css";
const TransactionList = ({ transactions }) => {
return (
<div className={styles.transactions}>
{transactions.map((transaction) => (
<li key={transaction.id}>
<p className={styles.name}>{transaction.name}</p>
<p className={styles.amount}>{transaction.amount}원</p>
</li>
))}
</div>
);
};
export default TransactionList;
Home.module.css
/* 트랜젝션 리스트 스타일 */
.transactions li {
margin: 30px auto;
border: 1px solid #f2f2f2;
box-shadow: 3px 3px 5px rgba(50, 50, 50, 0.1);
padding: 20px;
display: flex;
align-items: center;
position: relative;
overflow: hidden;
border-left: 4px solid #1f9751;
}
.transactions .name {
color: #777;
font-size: 1.4em;
}
.transactions .amount {
margin-left: auto;
margin-right: 40px;
color: #777;
font-weight: bold;
font-size: 1.6em;
}
.transactions button {
position: absolute;
top: 0;
right: 0;
background: #ddd;
color: #777;
border: none;
padding: 12px 8px;
text-align: center;
line-height: 0;
font-size: 0.9em;
cursor: pointer;
}
hong은 hong의 거래내역만 볼 수 있고
다른 유저로 로그인해서 확인해도 본인의 거래내역만 확인가능하다.
'FRONTEND > React' 카테고리의 다른 글
[마이머니앱] 보안 (0) | 2023.12.05 |
---|---|
[마이머니앱] 삭제하기 (1) | 2023.12.05 |
[마이머니앱] 네비게이션 가드 (0) | 2023.12.04 |
[마이머니앱] 클린업 함수 추가하기/ 로그인 및 로그인 시 유저정보 가져오기 (1) | 2023.12.04 |
[마이머니앱] 파이어베이스(DB) 사용/회원가입/로그아웃 (1) | 2023.12.04 |