Skip to content

Commit f6bed68

Browse files
committed
feat: 잔디 심는 로직 변경 (광클 시 무한대로 쌓이는 잔디 버그 해결)
1 parent 8d824c2 commit f6bed68

5 files changed

Lines changed: 91 additions & 74 deletions

File tree

components/heatmap/GrassHeatmap.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export default function GrassHeatmap({ uid }: Props) {
2727
}, [endDate]);
2828

2929
const [values, setValues] = useState<
30-
{ date: string; total: number; tilCount?: number; todoDoneCount?: number }[]
30+
{ date: string; total: number; tilCount?: number; planDoneCount?: number }[]
3131
>([]);
3232

3333
useEffect(() => {
@@ -41,12 +41,12 @@ export default function GrassHeatmap({ uid }: Props) {
4141
const byDate = useMemo(() => {
4242
const m = new Map<
4343
string,
44-
{ tilCount: number; todoDoneCount: number; total: number }
44+
{ tilCount: number; planDoneCount: number; total: number }
4545
>();
4646
for (const s of values) {
4747
m.set(s.date, {
4848
tilCount: s.tilCount ?? 0,
49-
todoDoneCount: s.todoDoneCount ?? 0,
49+
planDoneCount: s.planDoneCount ?? 0,
5050
total: s.total ?? 0,
5151
});
5252
}
@@ -81,7 +81,7 @@ export default function GrassHeatmap({ uid }: Props) {
8181
const d = byDate.get(value.date);
8282

8383
const til = d?.tilCount ?? 0;
84-
const todo = d?.todoDoneCount ?? 0;
84+
const todo = d?.planDoneCount ?? 0;
8585
const total = d?.total ?? 0;
8686

8787
return {
Lines changed: 59 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,79 @@
11
import {
22
doc,
3-
runTransaction,
4-
serverTimestamp,
3+
setDoc,
54
collection,
65
getDocs,
76
query,
87
where,
8+
serverTimestamp,
99
orderBy,
1010
getDoc,
11+
Timestamp,
1112
} from 'firebase/firestore';
1213
import { db } from '@/lib/firebase';
1314

1415
export interface DailyStat {
1516
date: string; // YYYY-MM-DD
16-
total: number;
17-
}
18-
19-
export type DailyStatDetail = {
20-
date: string;
2117
tilCount: number;
22-
todoDoneCount: number;
18+
planDoneCount: number;
2319
total: number;
24-
};
20+
updatedAt?: Timestamp;
21+
}
2522

2623
function dateKeyKST(date = new Date()) {
2724
const kst = new Date(date.getTime() + 9 * 60 * 60 * 1000);
2825
return kst.toISOString().slice(0, 10);
2926
}
3027

31-
export const bumpDailyStat = async (
32-
uid: string,
33-
deltaTil: number,
34-
deltaTodoDone: number
35-
) => {
36-
const key = dateKeyKST();
37-
const ref = doc(db, `users/${uid}/dailyStats/${key}`);
38-
39-
await runTransaction(db, async (tx) => {
40-
const snap = await tx.get(ref);
41-
42-
const prev = snap.exists()
43-
? (snap.data() as {
44-
tilCount?: number;
45-
todoDoneCount?: number;
46-
total?: number;
47-
})
48-
: {};
49-
50-
const nextTil = Math.max(0, (prev.tilCount ?? 0) + deltaTil);
51-
const nextTodo = Math.max(0, (prev.todoDoneCount ?? 0) + deltaTodoDone);
52-
const nextTotal = Math.max(0, nextTil + nextTodo);
53-
54-
tx.set(
55-
ref,
56-
{
57-
date: key,
58-
tilCount: nextTil,
59-
todoDoneCount: nextTodo,
60-
total: nextTotal,
61-
updatedAt: serverTimestamp(),
62-
},
63-
{ merge: true }
64-
);
65-
});
28+
const formatDate = (d: string | Date | undefined) => {
29+
if (!d) return '';
30+
if (typeof d === 'string') return d;
31+
return d.toISOString().split('T')[0]; // YYYY-MM-DD 형식
32+
};
33+
34+
export const recomputeDailyStat = async (uid: string) => {
35+
const dateKey = dateKeyKST();
36+
37+
/** 1. 오늘 완료된 planItems */
38+
39+
const planItemsRef = collection(db, 'users', uid, 'planItems');
40+
const planQuery = query(
41+
planItemsRef,
42+
where('dateKey', '==', dateKey),
43+
where('isChecked', '==', true)
44+
);
45+
const planSnap = await getDocs(planQuery);
46+
const planDoneCount = planSnap.size;
47+
48+
/** 2. 오늘 작성한 TIL */
49+
const tilRef = collection(db, 'users', uid, 'tils');
50+
const tilQuery = query(tilRef, where('dateKey', '==', dateKey));
51+
const tilSnap = await getDocs(tilQuery);
52+
const tilCount = tilSnap.size;
53+
54+
/** 3. DailyStat 덮어쓰기 */
55+
const ref = doc(db, 'users', uid, 'dailyStats', dateKey);
56+
57+
await setDoc(
58+
ref,
59+
{
60+
date: dateKey,
61+
tilCount,
62+
planDoneCount,
63+
total: tilCount + planDoneCount,
64+
updatedAt: serverTimestamp(),
65+
},
66+
{ merge: true }
67+
);
6668
};
6769

6870
export const fetchDailyStats = async (uid: string): Promise<DailyStat[]> => {
6971
const colRef = collection(db, 'users', uid, 'dailyStats');
7072

71-
const endDate = dateKeyKST(new Date());
72-
const startDate = (() => {
73-
const d = new Date();
74-
d.setFullYear(d.getFullYear() - 1);
75-
d.setDate(d.getDate() + 1);
76-
return dateKeyKST(d);
77-
})();
73+
const endDate = dateKeyKST();
74+
const start = new Date();
75+
start.setFullYear(start.getFullYear() - 1);
76+
const startDate = dateKeyKST(start);
7877

7978
const q = query(
8079
colRef,
@@ -85,21 +84,18 @@ export const fetchDailyStats = async (uid: string): Promise<DailyStat[]> => {
8584

8685
const snap = await getDocs(q);
8786

88-
return snap.docs.map((doc) => {
89-
const data = doc.data();
90-
return {
91-
date: data.date,
92-
tilCount: data.tilCount ?? 0,
93-
todoDoneCount: data.todoDoneCount ?? 0,
94-
total: data.total ?? 0,
95-
};
96-
});
87+
return snap.docs.map((d) => ({
88+
date: d.data().date,
89+
tilCount: d.data().tilCount ?? 0,
90+
planDoneCount: d.data().planDoneCount ?? 0,
91+
total: d.data().total ?? 0,
92+
}));
9793
};
9894

9995
export const fetchDailyStatByDate = async (
10096
uid: string,
101-
date: string // YYYY-MM-DD
102-
): Promise<DailyStatDetail | null> => {
97+
date: string
98+
): Promise<DailyStat | null> => {
10399
const ref = doc(db, 'users', uid, 'dailyStats', date);
104100
const snap = await getDoc(ref);
105101

@@ -109,7 +105,7 @@ export const fetchDailyStatByDate = async (
109105
return {
110106
date: data.date,
111107
tilCount: data.tilCount ?? 0,
112-
todoDoneCount: data.todoDoneCount ?? 0,
108+
planDoneCount: data.planDoneCount ?? 0,
113109
total: data.total ?? 0,
114110
};
115111
};

services/plans/planManageService.service.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
writeBatch,
1313
} from 'firebase/firestore';
1414
import { db } from '@/lib/firebase';
15-
import { bumpDailyStat } from '@/services/heatmap/dailyStat.service';
15+
import { recomputeDailyStat } from '@/services/heatmap/dailyStat.service';
1616

1717
// 플랜 데이터 타입
1818
export interface Plan {
@@ -30,6 +30,11 @@ export interface PlanItem {
3030
isChecked: boolean;
3131
deadline: Date;
3232
createdAt: Date;
33+
dateKey?: string;
34+
}
35+
function dateKeyKST(date = new Date()) {
36+
const kst = new Date(date.getTime() + 9 * 60 * 60 * 1000);
37+
return kst.toISOString().slice(0, 10);
3338
}
3439

3540
// 1. 플랜 생성하기
@@ -99,6 +104,7 @@ export const addPlanItem = async (
99104
isChecked: false,
100105
deadline: deadline ? Timestamp.fromDate(deadline) : null,
101106
createdAt: Timestamp.now(),
107+
dateKey: deadline ? dateKeyKST(deadline) : null,
102108
});
103109
};
104110

@@ -112,8 +118,7 @@ export const toggleItemStatus = async (
112118
await updateDoc(itemRef, {
113119
isChecked: !currentStatus,
114120
});
115-
const delta = !currentStatus ? 1 : -1;
116-
await bumpDailyStat(uid, 0, delta);
121+
await recomputeDailyStat(uid);
117122
};
118123

119124
// 6. 플랜 삭제
@@ -153,6 +158,7 @@ export const updatePlanItem = async (
153158
text?: string; // 수정할 제목
154159
description?: string; // 수정할 설명
155160
deadline?: Date | null; // 수정할 마감일 (null이면 마감일 삭제)
161+
dateKey?: string;
156162
}
157163
) => {
158164
const itemRef = doc(db, 'users', uid, 'planItems', itemId);
@@ -162,6 +168,7 @@ export const updatePlanItem = async (
162168
text?: string;
163169
description?: string;
164170
deadline?: Timestamp | null;
171+
dateKey?: string | null;
165172
} = {};
166173

167174
// 1. 제목이 전달되었으면 업데이트 목록에 추가
@@ -179,6 +186,9 @@ export const updatePlanItem = async (
179186
updatePayload.deadline = updates.deadline
180187
? Timestamp.fromDate(updates.deadline)
181188
: null; // null을 넘기면 DB에서 마감일이 사라짐
189+
updatePayload.dateKey = updates.deadline
190+
? dateKeyKST(updates.deadline)
191+
: null;
182192
}
183193

184194
// 변경사항이 있을 때만 DB 요청

services/write/til.service.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,19 @@ import {
1010
getCountFromServer,
1111
} from 'firebase/firestore';
1212
import { db } from '@/lib/firebase';
13-
import { bumpDailyStat } from '@/services/heatmap/dailyStat.service';
13+
import { recomputeDailyStat } from '@/services/heatmap/dailyStat.service';
14+
15+
function dateKeyKST(date = new Date()) {
16+
const kst = new Date(date.getTime() + 9 * 60 * 60 * 1000);
17+
return kst.toISOString().slice(0, 10);
18+
}
1419

1520
export type TilData = {
1621
title: string;
1722
content: string;
1823
createdAt: Timestamp | null;
1924
updatedAt: Timestamp | null;
25+
dateKey: string;
2026
};
2127

2228
export type Til = TilData & { id: string };
@@ -26,10 +32,11 @@ export async function createTil(uid: string, content: string, title: string) {
2632
const docRef = await addDoc(tilsCol, {
2733
title: title,
2834
content,
35+
dateKey: dateKeyKST(),
2936
createdAt: serverTimestamp(),
3037
updatedAt: serverTimestamp(),
3138
});
32-
await bumpDailyStat(uid, 1, 0);
39+
await recomputeDailyStat(uid);
3340
await fetchTilCount(uid);
3441
return docRef.id;
3542
}
@@ -48,11 +55,13 @@ const parseTilData = (raw: unknown): TilData | null => {
4855
const title = raw.title;
4956
if (typeof title !== 'string') return null;
5057

51-
const createdAt = raw.createdAt instanceof Timestamp ? raw.createdAt : null;
58+
const dateKey = raw.dateKey;
59+
if (typeof dateKey !== 'string') return null;
5260

61+
const createdAt = raw.createdAt instanceof Timestamp ? raw.createdAt : null;
5362
const updatedAt = raw.updatedAt instanceof Timestamp ? raw.updatedAt : null;
5463

55-
return { title, content, createdAt, updatedAt };
64+
return { title, content, dateKey, createdAt, updatedAt };
5665
};
5766

5867
export const fetchMyTil = async (
@@ -89,6 +98,7 @@ export const updateTil = async (
8998

9099
export const deleteTil = async (uid: string, tilId: string) => {
91100
await deleteDoc(doc(db, 'users', uid, 'tils', tilId));
101+
await recomputeDailyStat(uid);
92102
await fetchTilCount(uid);
93103
};
94104

types/til.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ export type TilDoc = {
1212
content: string;
1313
createdAt: Timestamp;
1414
updatedAt: Timestamp;
15+
dateKey: string;
1516
};

0 commit comments

Comments
 (0)