์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- url
- Fetch
- HTML
- Cloud
- SQL
- useEffect
- TMDB
- supabase
- IntersectionObserver
- jQuery
- this
- Boostrap
- Database
- db
- web
- data
- bootstrap
- nosql
- github
- CSS
- API
- REACT
- http
- W
- Protocol
- ๋ฐฐํฌ
- til
- JavaScript
- firestoredatabase
- Github Pages
- Today
- Total
072DATA
์บ๋ฆฐ๋์ ๋ฐ์ดํฐ ์๊ฐํํ๊ธฐ - ํน์ ๊ธฐ๊ฐ ์กฐํ ๋ฐ ๋ฐ์ดํฐ ์ ๋ฆฌ ๋ณธ๋ฌธ
์บ๋ฆฐ๋์ ๋ฐ์ดํฐ ์๊ฐํํ๊ธฐ - ํน์ ๊ธฐ๊ฐ ์กฐํ ๋ฐ ๋ฐ์ดํฐ ์ ๋ฆฌ
0720 2024. 11. 1. 02:00๐ 1. Supabase API ๊ตฌํ - ํน์ ๊ธฐ๊ฐ ๋ฐ์ดํฐ ์กฐํ
export const calendarApi = {
getByDateRange: async (startDate: string, endDate: string, userId: string) => {
try {
// ์ง์ ๋ ์์ ๋ฐ ์ข
๋ฃ ๋ ์ง์ ์๊ฐ ๋ฒ์๋ฅผ ์ค์
const startDateTime = `${startDate}T00:00:00.000Z`; // ์์ ๋ ์ง์ 00์ ์ค์
const endDateTime = `${endDate}T23:59:59.999Z`; // ์ข
๋ฃ ๋ ์ง์ 23์ 59๋ถ ์ค์
const { data, error } = await supabase
.from("challenges")
.select("*") // ๋ชจ๋ ์ปฌ๋ผ์ ์ ํ
.eq("user_id", userId) // ์ฌ์ฉ์์ ID์ ํด๋นํ๋ ํ์ ํํฐ๋ง
.gte("created_at", startDateTime) // ์์ ๋ ์ง ์ดํ์ ๋ฐ์ดํฐ๋ง ์ ํ
.lte("created_at", endDateTime) // ์ข
๋ฃ ๋ ์ง ์ด์ ์ ๋ฐ์ดํฐ๋ง ์ ํ
.order("created_at", { ascending: true }); // ๋ ์ง๋ณ๋ก ์ค๋ฆ์ฐจ์ ์ ๋ ฌ
if (error) throw error; // ์ค๋ฅ๊ฐ ์์ผ๋ฉด ์์ธ ๋ฐ์
return data; // ํํฐ๋ง๋ ๋ฐ์ดํฐ ๋ฐํ
} catch (error) {
console.error("๊ธฐ๊ฐ๋ณ ์ฑ๋ฆฐ์ง ์กฐํ ์ค๋ฅ:", error);
throw error; // ํธ์ถํ ํจ์๋ก ์์ธ ์ ๋ฌ
}
}
};
calendarApi.getByDateRange ํจ์๋ Supabase ๋ฐ์ดํฐ๋ฒ ์ด์ค์์
์ฌ์ฉ์ ์ง์ ๋ ์ง ๋ฒ์์ ํด๋นํ๋ ๋ฐ์ดํฐ๋ฅผ ํํฐ๋งํ์ฌ ๊ฐ์ ธ์ต๋๋ค.
startDate, endDate, userId๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์์
์ฃผ์ด์ง ๊ธฐ๊ฐ ๋ด์ ์์ฑ๋ ์ฌ์ฉ์์ ์ฑ๋ฆฐ์ง ๋ฐ์ดํฐ๋ฅผ ์กฐํํฉ๋๋ค.
๐ 2. ๋ฐ์ดํฐ ์ฒ๋ฆฌ - ๋ ์ง๋ณ ๋ฐ์ดํฐ ์ ๋ฆฌ
const fetchMonthlyData = async () => {
if (!userId) return; // userId๊ฐ ์์ผ๋ฉด ํจ์ ์ข
๋ฃ
try {
// ํ์ฌ ์์ ์์ ๋ฐ ์ข
๋ฃ ๋ ์ง๋ฅผ YYYY-MM-DD ํ์์ผ๋ก ์ค์
const startOfMonth = currentMonth.startOf("month").format("YYYY-MM-DD");
const endOfMonth = currentMonth.endOf("month").format("YYYY-MM-DD");
// ์ง์ ๋ ์์ ํด๋นํ๋ ์ฑ๋ฆฐ์ง ๋ฐ์ดํฐ ์กฐํ
const challengeData = await calendarApi.getByDateRange(
startOfMonth,
endOfMonth,
userId
);
// ๋ฐ์ดํฐ๋ฅผ ๋ ์ง๋ณ๋ก ์ ๋ฆฌ
const dataByDate: MonthlyData = {};
challengeData.forEach((item) => {
const date = item.created_at.split("T")[0]; // ํ์์คํฌํ์์ ๋ ์ง๋ง ์ถ์ถ (YYYY-MM-DD ํ์)
// ๋ ์ง๋ณ๋ก co2, point ๊ฐ์ ๋์ ๋๋ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ ์ฅ
dataByDate[date] = {
co2: item.co2 || 0,
point: item.point || 0,
challenge_count: 1
};
});
setMonthlyData(dataByDate); // ์ํ ์
๋ฐ์ดํธ
} catch (error) {
console.error("์บ๋ฆฐ๋ ๋ฐ์ดํฐ ์์ฒญ ์คํจ:", error);
}
};
fetchMonthlyData ํจ์๋ API์์ ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ฅผ ๋ ์ง๋ณ๋ก ์ ๋ฆฌํ์ฌ
์บ๋ฆฐ๋์ ํ์ํ ์ ๋๋ก ํด์คฌ์ต๋๋ค
์์ ์์๊ณผ ๋ ๋ ์ง๋ฅผ ์ ์ํ์ฌ ํ ๋ฌ์น ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ๋ค์
๋ฐ์ดํฐ์ created_at ํ์์คํฌํ์์ ๋ ์ง๋ง ์ถ์ถํ์ฌ ๋ ์ง๋ณ๋ก ์ ์ฅํฉ๋๋ค.
๐ 3. UI ๊ตฌํ - ๋ ์ง๋ณ ๋ฐ์ดํฐ ํ์
{week.map(({ day, isInCurrentMonth }) => {
const dateStr = day.format("YYYY-MM-DD"); // ๋ ์ง๋ฅผ YYYY-MM-DD ํ์์ผ๋ก ๋ณํ
const dayData = monthlyData[dateStr]; // ํด๋น ๋ ์ง์ ๋ฐ์ดํฐ
const today = new Date();
const isToday = day.format("YYYY-MM-DD") === dayjs(today).format("YYYY-MM-DD");
return (
<div className={`flex flex-col items-center p-4 ${!isInCurrentMonth ? "text-gray-400" : ""}`}>
<div className={`
w-10 h-10 font-medium flex items-center justify-center
${isToday ? "bg-red-500" : dayData ? "bg-gray-400" : ""}
${(isToday || dayData) && "rounded-full text-white"}
`}>
{day.format("D")}
</div>
{dayData && (
<>
<p className="text-sm font-medium">{dayData.co2.toFixed(2)}kg</p>
<p className="text-sm font-medium">+{dayData.point}P</p>
</>
)}
</div>
);
})}
์ฃผ์ด์ง ์ฃผ์ ๋ ์ง๋ค์ ๋ฐ๋ณตํ๋ฉด์ monthlyData์
์ ์ฅ๋ ๋ฐ์ดํฐ์ ๋งค์นญํ์ฌ ์บ๋ฆฐ๋ ์ ์ ํ์ํ์ผ๋ฉฐ
์กฐ๊ฑด์ ๋ฐ๋ผ ์ค๋ ๋ ์ง์ ๋ฐ์ดํฐ๊ฐ ์๋ ๋ ์ง์ ์คํ์ผ๋ง์ ์ถ๊ฐํด
์ฌ์ฉ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ง๊ด์ ์ผ๋ก ํ์ ํ ์ ์๊ฒ ํด์คฌ์ต๋๋ค
์ฌ์ฉํ ํ์
interface MonthlyData {
[key: string]: {
co2: number;
point: number;
challenge_count: number;
};
}
interface MonthlyStats {
totalCo2: number;
totalPoints: number;
totalChallenges: number;
}
โจ ๊ตฌํ ํฌ์ธํธ
- ๋ฐ์ดํฐ ์ ๋ฆฌ: ํ์์คํฌํ์์ ๋ ์ง ๋ถ๋ถ๋ง ๊ฐ์ ธ์ ์บ๋ฆฐ๋์์ ํค๋ก ์ฌ์ฉ
- ์กฐ๊ฑด๋ถ ์คํ์ผ๋ง: ์ค๋ ๋ ์ง์ ๋ฐ์ดํฐ๊ฐ ์๋ ๋ ์ง์ ์คํ์ผ์ ์ถ๊ฐํ์ฌ ์ฝ๊ฒ ๊ตฌ๋ณ ๊ฐ๋ฅ
- ์๊ฐ ํต๊ณ ๊ณ์ฐ: ํ ๋ฌ ๋์์ ์ด COโ ์ ๊ฐ๋, ํฌ์ธํธ, ์ฐธ์ฌ ํ์๋ฅผ ์กฐํ ๊ฐ๋ฅ
๐ก ๋ฐฐ์ด ์
- Supabase์์ ๋ ์ง๋ก ํํฐ๋งํ ๋๋ ์๊ฐ ๋ฒ์๋ฅผ ์ ํํ ์ค์ ํ๋ ๊ฒ ์ค์ํ๋ค๋ ์ .
- ํ์์คํฌํ๋ฅผ ์ฒ๋ฆฌํ ๋๋ ์๊ฐ๋ ์ฐจ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด UTC ํ์์ ์ฌ์ฉํ๊ธฐ
- ์บ๋ฆฐ๋์์ ๋ ์ง๋ณ ๋ฐ์ดํฐ๋ฅผ ๋งคํํ ๋ ์ผ๊ด๋ ๋ ์ง ํ์์ ์ฌ์ฉํ๋ ๊ฒ ์ค์
๋ง์น๋ฉฐ
์ํ๋ ๊ธฐ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์บ๋ฆฐ๋์ ํ์ํ ์ ์๊ฒ ๊ตฌํ์ด ์๋ฃ๋์๊ณ
์์ผ๋ก๋ ํ์ํ๋ค๋ฉด ์ ๋๋ฉ์ด์ ์ด๋ ์ํธ์์ฉ์ ์ถ๊ฐํ ๋ฏ ํ๋ค์ฅ
'FrontEnd > HTML, CSS, JavaScript' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Skeleton UI ์ ์ฉํ๊ธฐ ๐ฆด (0) | 2024.10.30 |
---|---|
๋ ๋ฒจ๋ง ์์คํ ๊ตฌํํ๊ธฐ (2) | 2024.10.30 |
๋ ์์ปฌ ํ๊ฒฝ๊ณผ ํด๋ก์ (0) | 2024.10.24 |
Throttling ์์๋ณด๊ธฐ ( ์ฑ๋ฅ ์ต์ ํ ๊ธฐ๋ฒ ) (1) | 2024.10.24 |
ํ ์คํธ(react-toastify) ์ฌ์ฉํ๊ธฐ (0) | 2024.09.20 |