-
-
-
+ className={styles.color}
+ style={{
+ backgroundColor: subscription.color || cssVarV2.button.primary,
+ }}
+ />
+
+
+ {subscription.displayName ?? subscription.externalCalendarId}
+ {subscription.timezone ? (
+
{subscription.timezone}
+ ) : null}
);
};
-
-const UnsubscribeButton = ({ url, name }: { url: string; name: string }) => {
- const t = useI18n();
- const calendar = useService(IntegrationService).calendar;
- const { openConfirmModal } = useConfirmModal();
-
- const handleUnsubscribe = useCallback(() => {
- openConfirmModal({
- title: t['com.affine.integration.calendar.unsubscribe'](),
- children: t.t('com.affine.integration.calendar.unsubscribe-content', {
- name,
- }),
- onConfirm: () => {
- calendar.deleteSubscription(url);
- track.$.settingsPanel.integrationList.disconnectIntegration({
- type: 'calendar',
- control: 'Calendar Setting',
- });
- },
- confirmText: t['com.affine.integration.calendar.unsubscribe'](),
- confirmButtonOptions: {
- variant: 'error',
- },
- });
- }, [calendar, name, openConfirmModal, t, url]);
-
- return (
-
- );
-};
-
-const ColorPicker = ({
- activeColor,
- onChange,
-}: {
- onChange: (color: string) => void;
- activeColor: string;
-}) => {
- const calendar = useService(IntegrationService).calendar;
- const colors = useMemo(() => calendar.colors, [calendar]);
-
- return (
-
- {colors.map(color => (
- - onChange(color)}
- data-active={color === activeColor}
- className={styles.colorPickerItem}
- style={{ color }}
- />
- ))}
-
- );
-};
diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/constants.tsx b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/constants.tsx
index 23a7e32d6..8719647ae 100644
--- a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/constants.tsx
+++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/constants.tsx
@@ -31,12 +31,13 @@ const INTEGRATION_LIST = [
icon:
,
setting:
,
},
- BUILD_CONFIG.isElectron && {
+ {
id: 'calendar' as const,
name: 'com.affine.integration.calendar.name',
desc: 'com.affine.integration.calendar.desc',
icon:
,
setting:
,
+ cloud: true,
},
{
id: 'mcp-server' as const,
diff --git a/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/journal/calendar-events.tsx b/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/journal/calendar-events.tsx
index c1791fc21..ebf193b22 100644
--- a/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/journal/calendar-events.tsx
+++ b/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/journal/calendar-events.tsx
@@ -16,21 +16,14 @@ import { useLiveData, useService } from '@toeverything/infra';
import { cssVarV2 } from '@toeverything/theme/v2';
import { assignInlineVars } from '@vanilla-extract/dynamic';
import type { Dayjs } from 'dayjs';
-import type ICAL from 'ical.js';
-import { useEffect, useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import * as styles from './calendar-events.css';
-const pad = (val?: number) => (val ?? 0).toString().padStart(2, '0');
-
-function formatTime(start?: ICAL.Time, end?: ICAL.Time) {
+function formatTime(start?: Dayjs, end?: Dayjs) {
if (!start || !end) return '';
- // Use toJSDate which handles timezone conversion for us
- const startDate = start.toJSDate();
- const endDate = end.toJSDate();
-
- const from = `${pad(startDate.getHours())}:${pad(startDate.getMinutes())}`;
- const to = `${pad(endDate.getHours())}:${pad(endDate.getMinutes())}`;
+ const from = start.format('HH:mm');
+ const to = end.format('HH:mm');
return from === to ? from : `${from} - ${to}`;
}
@@ -40,15 +33,6 @@ export const CalendarEvents = ({ date }: { date: Dayjs }) => {
useMemo(() => calendar.eventsByDate$(date), [calendar, date])
);
- useEffect(() => {
- const update = () => {
- calendar.subscriptions$.value.forEach(sub => sub.update());
- };
- update();
- const interval = setInterval(update, 5 * 60 * 1000);
- return () => clearInterval(interval);
- }, [calendar]);
-
return (
{events.map(event => (
@@ -60,9 +44,9 @@ export const CalendarEvents = ({ date }: { date: Dayjs }) => {
const CalendarEventRenderer = ({ event }: { event: CalendarEvent }) => {
const t = useI18n();
- const { url, title, startAt, endAt, allDay, date } = event;
+ const { title, startAt, endAt, allDay, date, calendarName, calendarColor } =
+ event;
const [loading, setLoading] = useState(false);
- const calendar = useService(IntegrationService).calendar;
const docsService = useService(DocsService);
const guardService = useService(GuardService);
const journalService = useService(JournalService);
@@ -70,21 +54,23 @@ const CalendarEventRenderer = ({ event }: { event: CalendarEvent }) => {
const { createPage } = usePageHelper(
workspaceService.workspace.docCollection
);
- const subscription = useLiveData(
- useMemo(() => calendar.subscription$(url), [calendar, url])
- );
- const config = useLiveData(
- useMemo(() => subscription?.config$, [subscription?.config$])
- );
- const name = useLiveData(subscription?.name$) || t['Untitled']();
- const color = config?.color || cssVarV2.button.primary;
+ const name = calendarName || t['Untitled']();
+ const color = calendarColor || cssVarV2.button.primary;
+ const eventTitle = title || t['Untitled']();
const handleClick = useAsyncCallback(async () => {
- if (!date || loading) return;
+ if (loading) return;
const docs = journalService.journalsByDate$(
date.format('YYYY-MM-DD')
).value;
- if (docs.length === 0) return;
+ if (docs.length === 0) {
+ toast(
+ t['com.affine.integration.calendar.no-journal']({
+ date: date.format('YYYY-MM-DD'),
+ })
+ );
+ return;
+ }
setLoading(true);
@@ -97,7 +83,7 @@ const CalendarEventRenderer = ({ event }: { event: CalendarEvent }) => {
}
const newDoc = createPage();
- await docsService.changeDocTitle(newDoc.id, title);
+ await docsService.changeDocTitle(newDoc.id, eventTitle);
await docsService.addLinkedDoc(doc.id, newDoc.id);
}
track.doc.sidepanel.journal.createCalendarDocEvent();
@@ -112,7 +98,7 @@ const CalendarEventRenderer = ({ event }: { event: CalendarEvent }) => {
journalService,
loading,
t,
- title,
+ eventTitle,
]);
return (
@@ -143,7 +129,7 @@ const CalendarEventRenderer = ({ event }: { event: CalendarEvent }) => {
{allDay ? : }
-