๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
IT/JavaScript โ–ช JQuery

[FullCalendar] ํ’€์บ˜๋ฆฐ๋” ์ฐจ๊ทผ์ฐจ๊ทผ ๋‹ฌ๋ ฅ ์ƒ์„ฑ1 (์ฃผ๋ง ์ƒ‰ ๋ณ€๊ฒฝ / ์‹œ๊ฐ„ ํ‘œ์‹œ ์ œ๊ฑฐ)

by YeonBu 2024. 2. 3.
728x90

 

 

* ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ

* FullCalendar๋Š” cdn ์‚ฌ์šฉ

* DB๋Š” Firebase ์‚ฌ์šฉ

* FullCalendar ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฌธ์„œ ์ฐธ๊ณ 

 

Event Parsing - Docs | FullCalendar

When you give your calendar event data, whether it’s through an array, a json feed, or the addEvent method, you specify the event as a plain JavaScript object with properties. This object then gets “parsed” into a proper Event Object that is then exp

fullcalendar.io

 


 

1. ๊ธฐ๋ณธ ์บ˜๋ฆฐ๋” ์ƒ์„ฑ

 

*HTML

<!-- ์บ˜๋ฆฐ๋” ์ƒ์„ฑ ์œ„์น˜ -->
<div id='calendar-container'>    
	<div id='calendar'></div>  
</div>

<!-- ๋ชจ๋‹ฌ -->
<div class="modal fade" id="addEventModal" tabindex="-1" aria-labelledby="addEventModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="addEventModalLabel">๊ณผ์ œ ์ถ”๊ฐ€</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <form id="eventForm">
                    <div class="mb-3">
                        <label for="subject" class="form-label">๊ณผ๋ชฉ</label>
                        <input type="text" class="form-control" id="subject" required>
                    </div>
                    <div class="mb-3">
                        <label for="title" class="form-label">๊ณผ์ œ</label>
                        <input type="text" class="form-control" id="title" required>
                    </div>
                    <div class="mb-3">
                        <label for="start" class="form-label">์‹œ์ž‘ ์ผ์ž</label>
                        <input type="date" class="form-control" id="start" required>
                    </div>
                    <div class="mb-3">
                        <label for="end" class="form-label">์ข…๋ฃŒ ์ผ์ž</label>
                        <input type="date" class="form-control" id="end" required>
                    </div>
                    <button type="submit" class="btn btn-primary">์ €์žฅ</button>
                </form>
            </div>
        </div>
    </div>
</div>

 

 

*JS

// fullcalendar ๋กœ๋“œ
document.addEventListener('DOMContentLoaded', function() {

    const calendarEl = document.getElementById('calendar');
    
    // FullCalendar ์˜ต์…˜ ์„ค์ •
    const calendar = new FullCalendar.Calendar(calendarEl, {
        initialView: 'dayGridMonth',
        selectable: true, // ๋‹ฌ๋ ฅ ์…€ ์„ ํƒ ํ™œ์„ฑํ™”
        select: function(info) {	// ๋‹ฌ๋ ฅ ์…€์„ ํด๋ฆญํ•  ๋•Œ ๋ชจ๋‹ฌ ์—ด๊ธฐ
            $('#addEventModal').modal('show'); 
            $('#start').val(info.startStr); 
            $('#end').val(info.endStr);
        },
        events: loadEvents // ์ผ์ • ๋ถˆ๋Ÿฌ์˜ค๊ธฐ(loadEvents ํ•จ์ˆ˜ ์ฐธ์กฐ) 
    });
    
    calendar.render();
    
    
    // ๊ณผ์ œ ์ถ”๊ฐ€ ํผ ์ œ์ถœ ์‹œ
    $('#eventForm').submit(function(e) {
        e.preventDefault(); // ํผ์˜ ๊ธฐ๋ณธ ๋™์ž‘ ๋ฐฉ์ง€

        // ์ž…๋ ฅ๋œ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
        const subject = $('#subject').val();
        const title = $('#title').val();
        const start = $('#start').val();
        const end = $('#end').val();

        docTime(); // ๊ณ ์œ ๋ฒˆํ˜ธ ๋ฆฌ์…‹(๊ฐœ์ธ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ณ ์œ ๋ฒˆํ˜ธ์ž„)
        
        // Firebase์— ๊ณผ์ œ ์ถ”๊ฐ€
        db.collection("events").doc(docName).set({
            docName : docName,
            subject : subject,
            title: title,
            start: start,
            end: end
        })
        .then(function() {
            $('#addEventModal').modal('hide'); // ๋ชจ๋‹ฌ ๋‹ซ๊ธฐ
            calendar.refetchEvents(); // ๋‹ฌ๋ ฅ ๊ฐฑ์‹ 
            resetForm(); // form ์ดˆ๊ธฐํ™”
        })
        .catch(function(error) {
            console.error("๊ณผ์ œ ์ถ”๊ฐ€ ์˜ค๋ฅ˜:", error);
        });
    });

    // Firebase์—์„œ ์ผ์ • ๊ฐ€์ ธ์˜ค๊ธฐ
    function loadEvents(fetchInfo, successCallback, failureCallback) {
        db.collection("events").get().then((querySnapshot) => {
            let events = [];
            querySnapshot.forEach((doc) => {
                const eventData = doc.data();
                events.push({
                    title: eventData.subject,
                    start: eventData.start,
                    end: eventData.end
                });
            });
            successCallback(events); // ๊ฐ€์ ธ์˜จ ์ด๋ฒคํŠธ ๋ฐฐ์—ด ์ „๋‹ฌ
        })
        .catch(function(error) {
            console.error("์ผ์ • ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์˜ค๋ฅ˜:", error);
            failureCallback(error); // ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์‹คํŒจ ์ฝœ๋ฐฑ ํ˜ธ์ถœ
        });
    }
    
  });

 

 

 


 

 

2. ์ฃผ๋ง ์ƒ‰ ๋ณ€๊ฒฝ

 

๊ทธ๋ƒฅ ๊ธฐ๋ณธ ์บ˜๋ฆฐ๋” ๋กœ๋“œํ–ˆ๋”๋‹ˆ ์ „์ฒด ํŒŒ๋ž€์ƒ‰์— ๋ง๋„์•ˆ๋˜๋Š” ๋ฐ‘์ค„.

์™œ ๋‹ค๋ฅธ์‚ฌ๋žŒ๋“ค์€ ์ „์ฒด ๊ฒ€์€์ƒ‰์ด๋˜๋ฐ ๋‚˜๋Š” ํŒŒ๋ž€์ƒ‰์ด์ง€..? ํ–ˆ๋Š”๋ฐ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ์„ ์‚ฌ์šฉํ•ด์„œ aํƒœ๊ทธ์— ๋ถ€๋”ชํ˜”๋‚˜๋ด„ใ…œ

 

 

*CSS

/* calendar.html */

.fc-col-header-cell-cushion, .fc-daygrid-day-number {
    text-decoration: none;
}

.fc-scrollgrid-sync-inner > .fc-col-header-cell-cushion,
.fc-day-mon .fc-daygrid-day-number,
.fc-day-tue .fc-daygrid-day-number,
.fc-day-wed .fc-daygrid-day-number,
.fc-day-thu .fc-daygrid-day-number,
.fc-day-fri .fc-daygrid-day-number {
    color: black;
}

.fc-day-sun .fc-col-header-cell-cushion,
.fc-day-sun a{
    color : red;
}

.fc-day-sat .fc-col-header-cell-cushion,
.fc-day-sat a {
    color : blue;
}

 


 

 

3. ์ผ์ • ์ถ”๊ฐ€

 

 

์ผ์ • ์ถ”๊ฐ€์— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ๋‹ค.

์œ„์ฒ˜๋Ÿผ 2์›” 5์ผ ~ 2์›” 6์ผ ์— ์ผ์ •์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์—ˆ๋Š”๋ฐ 5์ผ ํ•˜๋ฃจ์—๋งŒ ์ผ์ •์ด ์ถ”๊ฐ€ ๋œ ๊ฒƒ.

 

 

๋ฌธ์„œ๋ฅผ ์ฐพ์•„๋ณด๋‹ˆ

์‹œ๊ฐ„ ์„ค์ •์ด ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด 2์›” 6์ผ์— ์ผ์ •์ด ์ข…๋ฃŒ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ณ 

2์›” 5์ผ์—๋งŒ ์ผ์ •์ด ์ถ”๊ฐ€๋˜๋Š” ๊ฒƒ ๊ฐ™์•˜๋‹ค.

 

 

 

 

์‹ค์ œ๋กœ input type์„ 'date'๊ฐ€ ์•„๋‹ˆ๋ผ 'datetime-local'๋กœ ์„ค์ •ํ•ด์„œ ์‹œ๊ฐ„๊นŒ์ง€ ๋„ฃ์–ด์ฃผ๋ฉด

์ œ๋Œ€๋กœ ์ผ์ •์ด ์ถ”๊ฐ€๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

ํ•˜์ง€๋งŒ ๋‚˜๋Š” ์ผ์ •์ถ”๊ฐ€ํ•  ๋•Œ ๊ท€์ฐฎ๊ฒŒ ์‹œ๊ฐ„์„ ๋„ฃ๊ณ  ์‹ถ์ง€ ์•Š์•˜๋‹ค!

 

 

*JS

// Firebase์— ๊ณผ์ œ ์ถ”๊ฐ€
db.collection("events").doc(docName).set({
    docName : docName,
    subject : subject,
    title: title,
    start: start+"T00:00",
    end: end+"T23:59"
})

 

๊ทธ๋ž˜์„œ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ ์‹œ start + "T00:00", end + "T23:00" ์œผ๋กœ ๊ฐ•์ œ ์‹œ๊ฐ„ ์ž…๋ ฅํ•ด์คฌ๋‹ค.

 

 

 

์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 


 

4. ์‹œ๊ฐ„ ํ‘œ์‹œ ์ œ๊ฑฐ

 

์ผ์ • ์ถ”๊ฐ€ํ•˜๋Š” ๊ฑด ํ•ด๊ฒฐ ๋์œผ๋‚˜ ์ € ๋ชป์ƒ๊ธด 12a ๋ผ๊ณ  ๋‚˜์˜ค๋Š” ์‹œ๊ฐ„ ํ‘œ์‹œ ๋ถ€๋ถ„์„ ์ œ๊ฑฐ ํ•˜๊ณ  ์‹ถ์—ˆ๋‹ค.

 

*JS

// FullCalendar ์˜ต์…˜ ์„ค์ •
const calendar = new FullCalendar.Calendar(calendarEl, {
    initialView: 'dayGridMonth',
    selectable: true, // ๋‹ฌ๋ ฅ ์…€ ์„ ํƒ ํ™œ์„ฑํ™”
    displayEventTime: false, // ์‹œ๊ฐ„ ํ‘œ์‹œ ์ œ๊ฑฐ
	eventColor: '#990e17',
    select: function(info) {	// ๋‹ฌ๋ ฅ ์…€์„ ํด๋ฆญํ•  ๋•Œ ๋ชจ๋‹ฌ ์—ด๊ธฐ
        $('#addEventModal').modal('show'); 
        $('#start').val(info.startStr); 
        $('#end').val(info.endStr);
    },
    events: loadEvents // ์ผ์ • ๋ถˆ๋Ÿฌ์˜ค๊ธฐ(loadEvents ํ•จ์ˆ˜ ์ฐธ์กฐ) 
});

 

๋ฌธ์„œ์— ๋‚˜์™€์žˆ๋Š”๋Œ€๋กœ displayEventTime์„ false๋กœ ์ง€์ •ํ•ด์ฃผ๊ณ 

๊ฒธ์‚ฌ ๊ฒธ์‚ฌ ์ผ์ • ์ปฌ๋Ÿฌ๋ฅผ ํ˜„์žฌ ์‚ฌ์ดํŠธ์— ๋งž๋Š” ์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์—ˆ๋‹ค(= eventColor)

 

 

์™„์„ฑ!

 

 

๋ฐ˜์‘ํ˜•