Skip to main content

Frontend

The Calendar module has three frontend touchpoints: the connection panel in Business Settings, the "Add to Google Calendar" links scattered across module views, and a dedicated page with an embedded iframe.

File Structure​

resources/views/
├── calendar/
│ └── index.blade.php
└── settings/business/
└── _integrations.blade.php # Google Calendar connect/disconnect panel

Google Calendar links do not have their own views: they are integrated into the views of modules that implement CalendarEventable.

Connection Panel (Settings → Integrations)​

The Google Calendar section of _integrations.blade.php has two states, driven by $googleCalendar->isConnected() (the GoogleCalendarSettings singleton, passed in by BusinessSettingsController::edit()):

  • Disconnected — explanatory text + a "Connect" link to settings.google-calendar.connect
  • Connected — the linked Google account's email + a "Disconnect" button
Nested forms

The whole Integrations tab renders inside the main Business Settings <form>. A <form> cannot be nested in another one: the browser hoists it out of the DOM and the outer form loses its @method('PUT') spoofing, which makes saving settings fail with a 405 Method Not Allowed.

The "Disconnect" control is therefore a plain <button type="button"> that submits a hidden form declared outside the main form in settings/business.blade.php, the same pattern already used by "delete logo":

<button type="button" onclick="document.getElementById('google-calendar-disconnect-form').submit()">

Once connected, sync is fully automatic — there is no per-record "sync now" control anywhere in the UI. The manual links below still work and are unaffected.

Calendar Page (/calendar)​

Embedded iframe of the configured Google account's Google Calendar, within the application layout:

<iframe src="{{ env('GOOGLE_CALENDAR_EMBED_URL') }}"
style="width: 100%; height: calc(100vh - 130px); border: none;">
</iframe>

The iframe URL is read from the GOOGLE_CALENDAR_EMBED_URL environment variable. Set it in your .env file with the full embed URL from your Google Calendar settings. The user must be logged into the browser with the same Google account to view the calendar. The calendar does not need to be public.

Note: this page is not connected to the link builder system - it serves as an overview of events already created by the user in their Google Calendar.

Each model that implements CalendarEventable exposes buttons/links in its own views to add events to Google Calendar. The pattern is the same everywhere: an <a> link with target="_blank" pointing to the URL generated by googleCalendarUrl(), shown only if the model has a valid date.

ModuleViewCondition
Projectsprojects/show/_quick-info.blade.php$project->googleCalendarUrl() (project deadline)
Taskstasks/partials/_table-row-actions.blade.php$task->googleCalendarUrl() (task deadline)
Paymentspayments/partials/payment-table/_row-actions.blade.php$payment->googleCalendarUrl() (payment date)
Meetingsmeetings/partials/_meeting-table.blade.php$meeting->googleCalendarUrl() (meeting date)
Client follow-upsclients/followups/_list.blade.php$followup->googleCalendarUrl() (contact date)

UI Pattern​

All links follow the same pattern:

@if($model->googleCalendarUrl())
<a href="{{ $model->googleCalendarUrl() }}"
target="_blank"
...>
{{-- Calendar SVG icon --}}
</a>
@endif
  • Calendar SVG icon
  • target="_blank" to open in a new tab
  • Conditional: shown only if the model has a valid date (hasCalendarDate())
  • Style consistent with other table row actions

Usage Context​

  • Projects: link in the show sidebar, next to the deadline date
  • Tasks: icon in the actions column of the task table (both in index and project show)
  • Payments: icon in the actions column of the payments table
  • Meetings: icon in the actions column of the meetings table

Technical Notes​

  • No dedicated JS component: links are simple server-side generated <a href> elements.
  • The URL is generated by the model via GoogleCalendarLinkBuilder, no frontend logic involved.
  • The /calendar page iframe requires the user to be logged into the browser with the corresponding Google account. The URL is configured via the GOOGLE_CALENDAR_EMBED_URL env variable.