-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from treasure-sky/feat/notice-crud
- Loading branch information
Showing
6 changed files
with
279 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import { useState } from "react"; | ||
import { | ||
createNotice, | ||
getNoticeList, | ||
getNoticeById, | ||
updateNotice, | ||
deleteNotice, | ||
} from "./noticeService"; | ||
import { NoticeDto } from "../types/notice"; | ||
|
||
// 테스트용 컴포넌트 추후 삭제 예정 | ||
function FirebaseTest() { | ||
const [order, setOrder] = useState<number>(0); | ||
const [renewal, setRenewal] = useState<boolean>(false); | ||
const [title, setTitle] = useState<string>(""); | ||
const [contents, setContents] = useState<string>(""); | ||
const [createdAt, setCreatedAt] = useState<Date>(new Date()); | ||
const [notices, setNotices] = useState<NoticeDto[]>([]); | ||
const [noticeId, setNoticeId] = useState<string>(""); | ||
return ( | ||
<> | ||
<div> | ||
<h1>공지사항 생성</h1> | ||
<label> | ||
제목: | ||
<input type="text" value={title} onChange={(e) => setTitle(e.target.value)} /> | ||
</label> | ||
<label> | ||
내용: | ||
<input type="text" value={contents} onChange={(e) => setContents(e.target.value)} /> | ||
</label> | ||
<label> | ||
순서: | ||
<input type="text" value={order} onChange={(e) => setOrder(parseInt(e.target.value))} /> | ||
</label> | ||
<label> | ||
new 표시 여부: | ||
<input type="checkbox" checked={renewal} onChange={(e) => setRenewal(e.target.checked)} /> | ||
</label> | ||
<button | ||
onClick={async () => { | ||
await createNotice({ | ||
createdAt: new Date(), // 현재 시간으로 업데이트 | ||
order, | ||
renewal, | ||
title, | ||
contents, | ||
}); | ||
}} | ||
> | ||
생성 | ||
</button> | ||
</div> | ||
<div> | ||
<h1>전체 공지사항 조회</h1> | ||
<button | ||
onClick={async () => { | ||
const list = await getNoticeList(); | ||
setNotices(list); | ||
}} | ||
> | ||
조회 | ||
</button> | ||
<div> | ||
{notices.map((notice, index) => ( | ||
<div key={index}> | ||
{`ID: ${notice.id}, title: ${notice.title}, contents: ${notice.contents}, order: ${notice.order}, renewal: ${notice.renewal ? "O" : "X"}, createdAt: ${notice.createdAt}`} | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
<div> | ||
<h1>공지사항 조회 / 수정</h1> | ||
<label> | ||
공지사항 ID: | ||
<input type="text" value={noticeId} onChange={(e) => setNoticeId(e.target.value)} /> | ||
</label> | ||
<button | ||
onClick={async () => { | ||
const notice = await getNoticeById(noticeId); | ||
setNoticeId(notice.id); | ||
setTitle(notice.title); | ||
setContents(notice.contents); | ||
setOrder(notice.order); | ||
setRenewal(notice.renewal); | ||
setCreatedAt(notice.createdAt); | ||
}} | ||
> | ||
조회 | ||
</button> | ||
<label> | ||
제목: | ||
<input type="text" value={title} onChange={(e) => setTitle(e.target.value)} /> | ||
</label> | ||
<label> | ||
내용: | ||
<input type="text" value={contents} onChange={(e) => setContents(e.target.value)} /> | ||
</label> | ||
<label> | ||
순서: | ||
<input type="text" value={order} onChange={(e) => setOrder(parseInt(e.target.value))} /> | ||
</label> | ||
<label> | ||
new 표시 여부: | ||
<input type="checkbox" checked={renewal} onChange={(e) => setRenewal(e.target.checked)} /> | ||
</label> | ||
<button | ||
onClick={async () => { | ||
await updateNotice(noticeId, { | ||
createdAt, | ||
order, | ||
renewal, | ||
title, | ||
contents, | ||
}); | ||
}} | ||
> | ||
수정 | ||
</button> | ||
<button | ||
onClick={async () => { | ||
await deleteNotice(noticeId); | ||
}} | ||
> | ||
삭제 | ||
</button> | ||
</div> | ||
</> | ||
); | ||
} | ||
|
||
export default FirebaseTest; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { initializeApp } from "firebase/app"; | ||
import { getAnalytics } from "firebase/analytics"; | ||
import { getFirestore } from "firebase/firestore/lite"; | ||
|
||
const firebaseConfig = { | ||
apiKey: import.meta.env.VITE_FIREBASE_API_KEY, | ||
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN, | ||
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID, | ||
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET, | ||
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID, | ||
appId: import.meta.env.VITE_FIREBASE_APP_ID, | ||
measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID, | ||
}; | ||
|
||
const app = initializeApp(firebaseConfig); | ||
|
||
export const db = getFirestore(app); | ||
export const analytics = getAnalytics(app); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { | ||
DocumentData, | ||
FirestoreDataConverter, | ||
QueryDocumentSnapshot, | ||
Timestamp, | ||
} from "firebase/firestore/lite"; | ||
import { Notice } from "../types/notice"; | ||
|
||
// 유효성 검사 함수 | ||
function validation(notice: Notice) { | ||
if (!(notice.createdAt instanceof Date)) throw new Error("Invalid or missing createdAt."); | ||
if (typeof notice.order !== "number" || notice.order < 0) | ||
throw new Error("Invalid or missing order."); | ||
if (typeof notice.renewal !== "boolean") throw new Error("Invalid or missing renewal."); | ||
if (typeof notice.title !== "string" || !notice.title.trim()) | ||
throw new Error("Invalid or missing title."); | ||
if (typeof notice.contents !== "string" || !notice.contents.trim()) | ||
throw new Error("Invalid or missing contents."); | ||
} | ||
|
||
// Firestore data converter | ||
export const noticeConverter: FirestoreDataConverter<Notice> = { | ||
toFirestore(notice: Notice): DocumentData { | ||
validation(notice); | ||
return { | ||
createdAt: Timestamp.fromDate(notice.createdAt), // Date 객체를 Firestore Timestamp로 변환 | ||
order: notice.order, | ||
renewal: notice.renewal, | ||
title: notice.title, | ||
contents: notice.contents, | ||
}; | ||
}, | ||
fromFirestore(snapshot: QueryDocumentSnapshot): Notice { | ||
const data = snapshot.data(); | ||
const notice: Notice = { | ||
createdAt: data.createdAt.toDate(), // Firestore Timestamp를 Date 객체로 변환 | ||
order: data.order, | ||
renewal: data.renewal, | ||
title: data.title, | ||
contents: data.contents, | ||
}; | ||
validation(notice); | ||
return notice; | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { | ||
collection, | ||
addDoc, | ||
updateDoc, | ||
getDocs, | ||
getDoc, | ||
deleteDoc, | ||
doc, | ||
} from "firebase/firestore/lite"; | ||
import { Notice, NoticeDto } from "../types/notice"; | ||
import { db } from "./firebaseConfig"; | ||
import { noticeConverter } from "./noticeConverter"; | ||
|
||
// 공지사항 생성 | ||
export async function createNotice(newNotice: Notice) { | ||
try { | ||
const docRef = await addDoc(collection(db, "notice").withConverter(noticeConverter), newNotice); | ||
return docRef.id; | ||
} catch (e) { | ||
throw new Error("Error adding document: " + e); | ||
} | ||
} | ||
|
||
// 전체 공지사항 조회 | ||
export async function getNoticeList(): Promise<NoticeDto[]> { | ||
try { | ||
const querySnapshot = await getDocs(collection(db, "notice").withConverter(noticeConverter)); | ||
const result: NoticeDto[] = []; | ||
querySnapshot.forEach((doc) => { | ||
result.push({ id: doc.id, ...doc.data() }); | ||
}); | ||
return result; | ||
} catch (e) { | ||
throw new Error("Error getting documents: " + e); | ||
} | ||
} | ||
|
||
// 공지사항 조회 | ||
export async function getNoticeById(noticeId: string): Promise<NoticeDto> { | ||
try { | ||
const docRef = doc(db, "notice", noticeId).withConverter(noticeConverter); | ||
const docSnapshot = await getDoc(docRef); | ||
|
||
if (!docSnapshot.exists()) { | ||
throw new Error("No document found with id " + noticeId); // 문서가 없는 경우 예외 처리 | ||
} | ||
|
||
return { id: docSnapshot.id, ...docSnapshot.data() }; | ||
} catch (e) { | ||
throw new Error("Error getting document: " + e); | ||
} | ||
} | ||
|
||
// 공지사항 수정 | ||
export async function updateNotice(noticeId: string, newNotice: Notice) { | ||
try { | ||
const docRef = doc(db, "notice", noticeId).withConverter(noticeConverter); | ||
await updateDoc(docRef, { ...newNotice }); | ||
} catch (error) { | ||
throw new Error("Error updating document: " + error); | ||
} | ||
} | ||
|
||
// 공지사항 삭제 | ||
export async function deleteNotice(noticeId: string) { | ||
try { | ||
await deleteDoc(doc(db, "notice", noticeId)); | ||
} catch (error) { | ||
throw new Error("Error removing document: " + error); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// 공지사항 타입 | ||
export interface Notice { | ||
createdAt: Date; | ||
order: number; | ||
renewal: boolean; | ||
title: string; | ||
contents: string; | ||
} | ||
|
||
// 공지사항 반환 타입 | ||
export interface NoticeDto extends Notice { | ||
id: string; | ||
} |