Kawane Events Creator Portal — Part 4

Marc Cocchio
5 min readJan 18, 2024

First Part

The R and the D in CRUD: “Create, Read, Update, Delete.”

On my portal for event creators to contribute to a central Google calendar, I want logged in users to have the ability to view (Read) their own events within the portal, as well as to delete the events. I hesitate to add the ability to edit for a essentially reasons of simplicity. Mistakes do get made, plans and weather change, too, so the ability to delete one’s event is, in fact, useful in this case.

Not a hi-fidelity mockup a client would be pleased with.

Here’s what I need:

  • An additional “My events” page link in the navigation bar
  • A list of all events (and details) created by the logged in user
  • An intuitive “delete” button on each event
  • A delete confirmation modal (pop-up)

Working backwards, I kept my developer-mentor’s abbreviated words in my mind: “Programming is just a bunch of tiny little problems; if you can’t figure something out, break it into even small pieces.”

There is a unique id assigned by Google to every single calendar event. I need to get this id and save it to the database. Well, before I do that, I need to update my model.

protected $fillable = [
'event_title',
'start_date',
'start_time',
'end_date',
'end_time',
'description',
'location',
'google_calendar_id', // add this line
];

Run a migration to create the new column in my database table.

php artisan make:migration add_google_calendar_id_to_event_forms

Modify the generated migration file to add the column.

public function up()
{
Schema::table('event_forms', function (Blueprint $table) {
$table->string('google_calendar_id')->nullable()->after('location');
});
}

Run the migration to apply the changes.

php artisan migrate

Already, I’ve learned something. While technically it is possible to modify the original migration file, it's generally discouraged for several reasons. Version Control and History: migrations are a record of db changes over time, so this makes it clear when the google_calendar_id field was added. Plus, I can track changes and revert to previous versions if needed. Additionally, I am thinking about the future, collaborations, rerunning past migrations, and reversibility. Initially, I thought having fewer migration files was cleaner thus best practice. After some research, I learned that I was wrong.

Look at that, a new column in my database!

Next, I needed to actually fetch the google id, which spatie’s documentation assures me is simple.

Read the docs.

I had initially written the code to create events statically, but I refactored the code to be instance-based when including the id for readability.

// My initial static-based approach
Event::create([
'name' => $request->input('event_title'),
'startDateTime' => $startDateTime,
'endDateTime' => $endDateTime,
'description' => $request->input('description') . $additionalDescription,
'colorId' => $selectedcolor,
'visibility' => 'default',
'status' => 'confirmed',
]);
// Instance-based Approach
$event = new Event;
$event->name = $request->input('event_title');
$event->startDateTime = $startDateTime;
$event->endDateTime = $endDateTime;
$event->description = $request->input('description') . $additionalDescription;
$event->setColorId($selectedcolor);

$newEvent = $event->save();

// Retrieve Google Calendar event ID
$googleEventId = $newEvent->id;

// Retrieve the newly created (latest) EventForm instance
$eventForm = $request->user()->eventforms()->latest()->first();

// Assign the Google Calendar ID to the EventForm instance
$eventForm->google_calendar_id = $googleEventId;
$eventForm->save();
Excellent! Each event a user created is now associated with a unique Google Calendar ID in the database.

Next, I need to:

  • create a new “My Events” route
  • fetch and all non-deleted events associated with a user (with the most recent event being first; not the most recently created )
  • create a delete button
  • make a confirmation modal
  • Actually delete the event from the Google Calendar
Spatie’s docs

Second Part

I came up with a rather clever idea.

Show a list of ‘My Events’ that have an associated google_calendar_id and that have not been manually deleted from Google Calendar itself.

<h3>{{  __('My Events') }}</h3>
<p class="lead">{{ __('Here is a list of events which you have created.') }}</p>

<!-- Bootstrap's accordion -->
<div class="accordion" id="accordionOfEvents">
<!-- Loop through all of users events in the database -->
@foreach ($events as $index => $event)
<!--Display all of your events which have a google_calendar_id -->
@if ($event->google_calendar_id)
@php
// Check if the event exists on Google Calendar
$eventOnCalendar = \Spatie\GoogleCalendar\Event::find($event->google_calendar_id);
@endphp
<!-- Check if it was manually deleted directly on Google Calendar -->
@if ($eventOnCalendar && $eventOnCalendar->status !== 'cancelled')
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse{{ $index }}" aria-expanded="false" aria-controls="collapse{{ $index }}">
{{ $event->start_date ?? 'N/A' }} - {{ $event->event_title }}
</button>
</h2>
<div id="collapse{{ $index }}" class="accordion-collapse collapse" data-bs-parent="#accordionOfEvents">
<div class="accordion-body">
{{ $event->description ?? 'N/A' }}
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button type="button" class="btn btn-outline-danger btn-sm" data-bs-toggle="modal" data-bs-target="#staticBackdrop{{ $event->id }}">{{ __('Delete') }}</button>
</div>
</div>
</div>
</div>

<!-- The modal is inside the loop in order have a mtching id -->
<div class="modal fade" id="staticBackdrop{{ $event->id }}" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="staticBackdropLabel">{{ __('Are you sure?') }}</h1>
</div>
<div class="modal-body">
{{ __('This will remove your event from the Google Calendar. This cannot be undone.') }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ __('Cancel') }}</button>
<form id="delete-form" action="{{ route('eventforms.destroy', $event->id) }}" method="post">
@csrf
@method('delete')
<button type="submit" class="btn btn-danger">{{ __('Delete Event') }}</button>
</form>
</div>
</div>
</div>
</div>
@endif
@endif
@endforeach
</div>

The controller is clever, too:

    public function destroy(EventForm $eventForm)
{
// Check if the authenticated user is the owner of the event
if (auth()->user()->id !== $eventForm->user_id) {
abort(403); // non-authorized users can't delete others' events
}

// Delete the event from Google Calendar using Spatie package
Event::find($eventForm->google_calendar_id)->delete();

// Update the event in the database (set google_calendar_id to NULL)
$eventForm->update(['google_calendar_id' => null]);

// Redirect back or to a specific page after deletion
return redirect()->back()->with('success', 'Event deleted successfully');
}
I like accordions.
“Delete Event” will replace the db google_calendar_id with (NULL) as well as remove the event from the actual Google Calendar. The rest of the data persists in the database.
Deleting directly on Google Calendar (which only a few admins have access to) marks the event status as ‘cancelled’, so it won’t show up in ‘My Events’ anymore. Initially I had an issue with using Spatie’s package to delete an event that had already been removed from Google Calendar. This solved that.

Kawane Events — Part 1 :: Part 2 :: Part 3 :: Part 4

--

--

Marc Cocchio

Both a creative and critical thinker, I am a Python programmer, UX designer, and woodworker, based in Japan.