ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

RBC์— ๋Œ€ํ•œ ๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋Šฅ ๋ฐ ์„ค์ •์€ ์–ผ์ถ” ๋งˆ๋ฌด๋ฆฌ๋˜๊ณ , ์‹ค์ œ ๋ฐ์ดํ„ฐ์™€ ์—ฐ๋™ํ•˜๊ณ ์ž ํ•œ๋‹ค.

supabase ํ…Œ์ด๋ธ”์— ์ ์šฉ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ ์บ˜๋ฆฐ๋”์— ์ถœ๋ ฅํ•ด๋ณด์•˜๋‹ค.


supabase ํ…Œ์ด๋ธ” ์—ฐ๊ฒฐ ์„ค์ •์€ ๊ฐ„๋žตํžˆ ์•„๋ž˜์™€ ๊ฐ™์ด ์ง„ํ–‰ํ–ˆ๋‹ค.

  1. ํŽ˜์ด์ง€, ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ ๋ฐ ์—ฐ๊ฒฐ
  2. supabaseClient ์ƒ์„ฑ (supabaseClient.ts)
  3. plans ํ…Œ์ด๋ธ” ๊ฐ’ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ๋กœ์ง (supabaseApi.ts)
  4. plans ํƒ€์ž… ์ง€์ •
  5. ์ปดํฌ๋„ŒํŠธ์—์„œ ํ˜ธ์ถœ : useState, useEffect

 

 

new Date()

 

์ดˆ๊ธฐ๊ฐ’์„ ๋นˆ ๋ฐฐ์—ด๋กœ ๋‘์–ด ์ด๋ฒคํŠธ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜์˜€๋‹ค.

ํ•˜์ง€๋งŒ state์˜ ํƒ€์ž…์„ <plans[]>๋กœ ์ง€์ •ํ•˜์˜€์„ ๋•Œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

 

์—๋Ÿฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‚˜ํƒ€๋‚ฌ๋‹ค.

"์ด ํ˜ธ์ถœ๊ณผ ์ผ์น˜ํ•˜๋Š” ์˜ค๋ฒ„๋กœ๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. '"start"' ํ˜•์‹์€~ , '"end"' ํ˜•์‹์€~"

 

์—๋Ÿฌ ์›์ธ์€ supabase์˜ ๋ฐ์ดํ„ฐ ๊ฐ’๊ณผ RBC๊ฐ€ ํ•„์š”ํ•œ ๊ฐ’์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  • supabase : start_date์™€ end_date ๋ชจ๋‘ string
  • RBC : start์™€ end ๋ชจ๋‘ Date ํ•„์š”

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์€ supabase์˜ ๊ฐ’์„ ์•Œ๋งž๊ฒŒ ๋งคํ•‘ํ•˜๊ธฐ.

์ฆ‰, Date ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด new Date()๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

์ •๋ฆฌํ•˜์ž๋ฉด

  • new Date() ์‚ฌ์šฉ ์ด์œ 
    1. number์™€ string ํ˜•์‹์€ Date ํ˜•์‹์— ํ• ๋‹นํ•  ์ˆ˜ ์—†๋‹ค.
    2. ์ฆ‰, RBC์—์„œ๋Š” "start"์™€ "end" ํ•„๋“œ๊ฐ€ Date ๊ฐ์ฒด์—ฌ์•ผ ํ•œ๋‹ค.
    3. Supabase์—์„œ ๋ฐ›์•„์˜ค๋Š” start_date์™€ end_date์˜ type์€ string.
    4. ์ด ๋‘˜์„ ์ง์ ‘ Date ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ : new Date()

state ํƒ€์ž…์€ <CalendarEvent[]>๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

 

๐Ÿ“ŒType๊ณผ ์ตœ์ข… ๋กœ์ง

๋”๋ณด๊ธฐ
export interface PlansType {
  plan_id: string;
  created_at: number;
  user_id: string;
  contacts_id: string;
  start_date: string;
  end_date: string;
  title: string | null;
  detail: string | null;
  priority: string | null;
}

export interface CalendarEventType {
  id: string;
  title: string | null;
  start: Date;
  end: Date;
}
// src > components > commons > calendar.tsx

'use client';
import { Calendar, dateFnsLocalizer } from 'react-big-calendar';
import { format, parse, startOfWeek, getDay } from 'date-fns';
import { enUS } from 'date-fns/locale/en-US';
import { ko } from 'date-fns/locale/ko';
import { getPlans } from '@/lib/utils/supabaseApi';
import { useEffect, useState } from 'react';
import { CalendarEventType } from '@/types/plans';

// ๋กœ์ผ€์ผ(์ง€์—ญํ™”) ์„ค์ •
const locales = {
  'en-US': enUS, //๋ฏธ๊ตญ-์˜์–ด : ๋ฏธ๊ตญ์‹ ๋‚ ์งœ
  'ko-KR': ko, //ํ•œ๊ตญ-ํ•œ๊ธ€ : ํ•œ๊ตญ์‹ ๋‚ ์งœ
};

const localizer = dateFnsLocalizer({
  format,
  parse,
  startOfWeek,
  getDay,
  locales,
});

const MainCalendar = () => {
  const [events, setEvents] = useState<CalendarEventType[]>([]);

  useEffect(() => {
    const fetchEvents = async () => {
      try {
        const plans = await getPlans();

        const formatted = plans.map(
          (plan): CalendarEventType => ({
            id: plan.plan_id,
            title: plan.title,
            start: new Date(plan.start_date),
            end: new Date(plan.end_date),
          })
        );
        setEvents(formatted);
      } catch (error) {
        console.error('์ผ์ • ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ ์—๋Ÿฌ', error);
      }
    };
    fetchEvents();
  }, []);

  return (
    <div>
      <Calendar
        localizer={localizer}
        events={events} // ์—ฌ๊ธฐ์— ์ด๋ฒคํŠธ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ
        startAccessor='start'
        endAccessor='end'
        style={{ height: 500 }}
      />
    </div>
  );
};

export default MainCalendar;

 

๋‹ฌ๋ ฅ๊ณผ DB์˜ ๊ฐ’ ์ฐจ์ด : UTC

 

supabase ๋ฐ์ดํ„ฐ ์ค‘ ์‹œ์ž‘์ผ๊ณผ ์ข…๋ฃŒ์ผ์ด ๋‹ฌ๋ ฅ๊ณผ ๋‹ค๋ฅด๊ฒŒ ๋‚˜ํƒ€๋‚ฌ๋‹ค.

 

supabase์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ timestamptz (ํƒ€์ž„์Šคํƒฌํ”„ with ํƒ€์ž„์กด)์œผ๋กœ ๋‘๋ฉด

๊ฐ’์ด ์ถ”๊ฐ€๋  ๋•Œ ์ž์ฒด์ ์œผ๋กœ ์„ธ๊ณ„ํ‘œ์ค€์‹œ๊ฐ„(UTC)์„ ์ ์šฉํ•œ๋‹ค.

 

๋‚˜์˜ ์ž…์žฅ์—์„œ๋Š” ๋ฐ์ดํ„ฐ -> ๋ธŒ๋ผ์šฐ์ € ์ถœ๋ ฅ ์ด๋‹ค. ๋•Œ๋ฌธ์— ํ…Œ์ด๋ธ”์— ์ €์žฅ๋œ ๊ฐ’์œผ๋กœ๋ถ€ํ„ฐ ํ•˜๋ฃจ๊ฐ€ ๋ฐ€๋ ค์„œ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์œผ๋กœ ๋А๊ปด์ง€์ง€๋งŒ

์‚ฌ์šฉ์ž ์ž…์žฅ์—์„œ๋Š” ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘ -> ๋ฐ์ดํ„ฐ ์ €์žฅ ์ด๋‹ค. ๋•Œ๋ฌธ์— ์‹ค์ œ ์‚ฌ์šฉ์ž๋Š” 9์ผ ๋ฐฅ ๋จน๊ธฐ ์ผ์ •์„ ์ถ”๊ฐ€ํ–ˆ์ง€๋งŒ -9์‹œ๊ฐ„(ํ•œ๊ตญ ๊ธฐ์ค€ UTC์ฒ˜๋ฆฌ)๊ฐ€ ๋˜์–ด supabase์— ์ €์žฅ์ด ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

(๋ธŒ๋ผ์šฐ์ €)4์›” 9์ผ 00:00:00 ๋กœ ์„ ํƒ -> (supabase) 4์›” 8์ผ 15:00:00 ์ €์žฅ

 

 

์—ฐ์† ์ผ์ • ์ฒ˜๋ฆฌ - ์ข…๋ฃŒ์ผ ์ •๊ฐ

๋”ฐ๋ผ์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•œ ์‹œ๊ฐ„์— ๋งž์ถ”์–ด ๋‹ฌ๋ ฅ์— ์ž˜ ์ถœ๋ ฅ๋œ๋‹ค.

ํ•˜์ง€๋งŒ ์ด๋Š” ๋‹จ์ผ ์ผ์ •์—๋งŒ ์ ์šฉ์ด ๋˜๊ณ , ์—ฐ์† ์ผ์ •์—๋Š” ์กฐ๊ธˆ ๋‹ค๋ฅธ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

 

 

 

 

์œ„์˜ test ์ผ์ •์€ ๋ชจ๋‘ 5์ผ ์ผ์ •์ด๋‹ค. ํ•˜์ง€๋งŒ test-15๋Š” 4์ผ ์ผ์ •์œผ๋กœ ์ถœ๋ ฅ๋œ๋‹ค. ์™œ ๊ทธ๋Ÿด๊นŒ??

๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜์ž๋ฉด ์ข…๋ฃŒ์ผ ์‹œ๊ฐ„์ด ์ •๊ฐ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

test-15 ์‹œ์ž‘์ผ
test-15 ์ข…๋ฃŒ์ผ

test-15์˜ ์ผ์ • ๋ฐ์ดํ„ฐ์ด๋‹ค.

์ผ์ • ์‹œ์ž‘์ผ์„ ๋ณด๋ฉด UTC๊ฐ€ ์ ์šฉ๋˜์–ด 13์ผ๋กœ ์ €์žฅ๋˜์–ด์žˆ์ง€๋งŒ formatted ๊ฐ’์€ 14์ผ ์ •๊ฐ์ด๋‹ค.

์ผ์ • ์ข…๋ฃŒ์ผ์„ ๋ณด๋ฉด UTC๊ฐ€ ์ ์šฉ๋˜์–ด 17์ผ๋กœ ์ €์žฅ๋˜์–ด์žˆ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ formatted ๊ฐ’์„ ๋ณด๋ฉด 18์ผ ์ •๊ฐ์ด๋‹ค.

 

์‹œ์ž‘์ผ์€ formatted ๋ฐ์ดํ„ฐ๊ฐ€ ์ •๊ฐ์ด์–ด๋„ ์‹œ์ž‘ํ•˜๋Š” ๋‚ ์ด๊ธฐ์— ์ •์ƒ์ ์œผ๋กœ ํ‘œ์‹œ๋˜์ง€๋งŒ

์ข…๋ฃŒ์ผ์€ ์ •๊ฐ ์‹œ๊ฐ„์ด ์ ์šฉ๋˜์–ด 18์ผ ์ด์ „๊นŒ์ง€๋งŒ ๋‹ฌ๋ ฅ์— ํ‘œ์‹œ๋œ๋‹ค.

 

๋”ฐ๋ผ์„œ ์ข…๋ฃŒ์ผ์„ 1์‹œ๊ฐ„ ์ •๋„ ๋Š˜๋ ค ์ ์šฉ์‹œํ‚ค๋ฉด(์ผ์ • ์ž…๋ ฅ ๊ธฐ๋Šฅ ๋‹ด๋‹น ํŒ€์› ๋ถ„์ด ์ ์šฉ)

 

์ข…๋ฃŒ์ผ์ด 18์ผ ์˜ค์ „ 1์‹œ๋กœ ์„ค์ •๋˜์–ด ์œ„์˜ ๋‹ฌ๋ ฅ์ฒ˜๋Ÿผ(test-16) ์ž˜ ์ถœ๋ ฅ๋œ๋‹ค.

๊ณต์ง€์‚ฌํ•ญ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
์ตœ๊ทผ์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€
Total
Today
Yesterday
๋งํฌ
TAG
more
ยซ   2026/03   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
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
๊ธ€ ๋ณด๊ด€ํ•จ