Addon Categories
Calendars
Integrate external calendars (Google Calendar, Outlook) to synchronize appointments and turn them into tracked time.
Calendars (Schedules & Meetings)
This category example is conceptual and uses old contracts. Do not copy its APIs as a reference for the current SDK; consult Vault and Events and the contracts exported by
@mr-tick/sdk.
Calendars addons connect Mr. Tick to providers such as Google Calendar, Microsoft Outlook / 365, and iCal calendars.
This integration displays daily appointments in Mr. Tick's calendar view, allowing users to turn past meetings into actual time entries with one click.
🎯 Calendar Event Structure
To populate Mr. Tick's interface, a calendar plugin normalizes external events into a standard structure:
export interface CalendarEventDTO {
id: string // Identificador único do evento no provedor externo
title: string // Título ou assunto da reunião
description?: string // Pauta ou descrição do evento
startDate: Date // Data e hora de início
endDate: Date // Data e hora de término
attendeesCount?: number // Quantidade de participantes
meetLink?: string // Link da chamada (Google Meet, Teams, Zoom)
isAllDay?: boolean // Indica se é um evento de dia inteiro
}💻 Calendar Implementation Example
1. manifest.yaml
id: google-calendar-addon
name: Google Calendar Integration
version: 1.0.0
description: Sincroniza reuniões do Google Calendar com o Mr-tick
author: Sua Empresa <contato@empresa.com>
main: dist/index.js2. src/index.ts
import { AppError, Either } from '@mr-tick/sdk'
import type { IAddon, AddonContext } from '@mr-tick/sdk'
export interface CalendarEventDTO {
id: string
title: string
startDate: Date
endDate: Date
meetLink?: string
}
interface GoogleCalendarApiItem {
id: string
summary?: string
start: { dateTime?: string; date?: string }
end: { dateTime?: string; date?: string }
hangoutLink?: string
}
interface GoogleCalendarApiResponse {
items?: GoogleCalendarApiItem[]
}
export default class GoogleCalendarAddon implements IAddon {
private context: AddonContext | null = null
public activate(context: AddonContext): void {
this.context = context
context.contributions.settings.register([
{
id: 'general',
label: 'Geral',
groups: [
{
id: 'calendar_config',
label: 'Configurações do Calendário',
fields: [
{
id: 'calendarId',
label: 'ID do Calendário',
type: 'text',
defaultValue: 'primary',
description:
'Identificador do calendário (use "primary" para o principal).',
},
],
},
],
},
])
console.log('[GoogleCalendar] Addon ativado com sucesso!')
}
public deactivate(): void {
this.context = null
}
// Busca os eventos do dia especificado
public async fetchDayEvents(targetDate: Date, workspaceId: string): Promise<Either<AppError, CalendarEventDTO[]>> {
if (this.context === null) return Either.failure(AppError.Internal('ADDON_NOT_ACTIVE'))
const storedToken = await this.context.host.vault.get(
{ kind: 'workspace', workspaceId },
'accessToken',
)
if (storedToken.isFailure()) return storedToken.forwardFailure()
const accessToken = storedToken.success
if (accessToken === null) return Either.failure(AppError.Unauthorized('GOOGLE_CALENDAR_AUTH_REQUIRED'))
const startOfDay = new Date(targetDate)
startOfDay.setHours(0, 0, 0, 0)
const endOfDay = new Date(targetDate)
endOfDay.setHours(23, 59, 59, 999)
const url = new URL(
'https://www.googleapis.com/calendar/v3/calendars/primary/events',
)
url.searchParams.set('timeMin', startOfDay.toISOString())
url.searchParams.set('timeMax', endOfDay.toISOString())
url.searchParams.set('singleEvents', 'true')
url.searchParams.set('orderBy', 'startTime')
const response = await fetch(url.toString(), {
headers: { Authorization: `Bearer ${accessToken}` },
})
const data: GoogleCalendarApiResponse = await response.json()
const events = (data.items || []).map((item: GoogleCalendarApiItem): CalendarEventDTO => ({
id: item.id,
title: item.summary || 'Sem título',
startDate: new Date(item.start.dateTime || item.start.date || targetDate),
endDate: new Date(item.end.dateTime || item.end.date || targetDate),
meetLink: item.hangoutLink,
}))
return Either.success(events)
}
}🚀 Quick Conversion to Time Entries
When a user views meetings in Mr. Tick:
- Mr. Tick highlights meetings that have already ended.
- The "Log Time" button opens a prefilled form with the meeting title, calculated duration (
(endDate - startDate)), and suggested activity. - Saving creates a
TimeEntryentity and sends it to the Synchronization Engine.