Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion apps/desktop/src/components/devtool/seed/shared/calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ export const createCalendar = () => {
"Shared Calendar",
]);

const calendarId = id();
return {
id: id(),
id: calendarId,
data: {
user_id: DEFAULT_USER_ID,
tracking_id_calendar: `mock-${calendarId}`,
name: template,
created_at: faker.date.past({ years: 1 }).toISOString(),
enabled: faker.datatype.boolean(),
Expand Down
4 changes: 3 additions & 1 deletion apps/desktop/src/components/devtool/seed/shared/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,12 @@ export const createEvent = (calendar_id: string) => {
description = faker.helpers.arrayElement(topics);
}

const eventId = id();
return {
id: id(),
id: eventId,
data: {
user_id: DEFAULT_USER_ID,
tracking_id_event: `mock-${eventId}`,
calendar_id,
title,
started_at: startsAt.toISOString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ export function ParticipantChip({ mappingId }: { mappingId: string }) {

const assignedHumanId = details?.humanId;
const sessionId = details?.sessionId;
const source = details?.source;

const handleRemove = useRemoveParticipant({
mappingId,
assignedHumanId,
sessionId,
source,
});

const handleClick = useCallback(() => {
Expand All @@ -29,7 +31,7 @@ export function ParticipantChip({ mappingId }: { mappingId: string }) {
}
}, [assignedHumanId]);

if (!details) {
if (!details || source === "excluded") {
return null;
}

Expand Down Expand Up @@ -64,6 +66,12 @@ function useParticipantDetails(mappingId: string) {
mappingId,
main.STORE_ID,
);
const source = main.UI.useCell(
"mapping_session_participant",
mappingId,
"source",
main.STORE_ID,
);

if (!result) {
return null;
Expand All @@ -81,6 +89,7 @@ function useParticipantDetails(mappingId: string) {
orgId: (result.org_id as string | undefined) || undefined,
orgName: result.org_name as string | undefined,
sessionId: result.session_id as string,
source: source as string | undefined,
};
}

Expand All @@ -106,10 +115,12 @@ function useRemoveParticipant({
mappingId,
assignedHumanId,
sessionId,
source,
}: {
mappingId: string;
assignedHumanId: string | undefined;
sessionId: string | undefined;
source: string | undefined;
}) {
const store = main.UI.useStore(main.STORE_ID);
const indexes = main.UI.useIndexes(main.STORE_ID);
Expand Down Expand Up @@ -153,6 +164,12 @@ function useRemoveParticipant({
}
}

store.delRow("mapping_session_participant", mappingId);
}, [store, indexes, mappingId, assignedHumanId, sessionId]);
if (source === "auto") {
store.setPartialRow("mapping_session_participant", mappingId, {
source: "excluded",
});
} else {
store.delRow("mapping_session_participant", mappingId);
}
}, [store, indexes, mappingId, assignedHumanId, sessionId, source]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ function useLinkHumanToSession(
created_at: new Date().toISOString(),
session_id: sessionId,
human_id: p.humanId,
source: "manual",
}),
[userId, sessionId],
main.STORE_ID,
Expand Down
46 changes: 22 additions & 24 deletions apps/desktop/src/components/settings/calendar/configure/apple.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { AlertCircleIcon, ArrowRightIcon, CheckIcon } from "lucide-react";
import { useMemo } from "react";

import {
type AppleCalendar,
commands as appleCalendarCommands,
colorToCSS,
} from "@hypr/plugin-apple-calendar";
Expand All @@ -21,6 +20,7 @@ import { Button } from "@hypr/ui/components/ui/button";
import { cn } from "@hypr/utils";

import * as main from "../../../../store/tinybase/main";
import { findCalendarByTrackingId } from "../../../../utils/calendar";
import { PROVIDERS } from "../shared";
import {
type CalendarGroup,
Expand Down Expand Up @@ -188,25 +188,6 @@ function useAppleCalendarSelection() {
const calendars = main.UI.useTable("calendars", main.STORE_ID);
const { user_id } = main.UI.useValues(main.STORE_ID);

const setCalendarRow = main.UI.useSetRowCallback(
"calendars",
(cal: AppleCalendar) => cal.id,
(cal: AppleCalendar, store) => {
const existing = store.getRow("calendars", cal.id);
return {
user_id: user_id!,
created_at: existing?.created_at || new Date().toISOString(),
name: cal.title,
enabled: existing?.enabled ?? false,
provider: "apple",
source: cal.source.title,
color: colorToCSS(cal.color),
};
},
[user_id],
main.STORE_ID,
);

const { mutate: syncCalendars, isPending } = useMutation({
mutationKey: ["appleCalendars", "sync"],
mutationFn: async () => {
Expand All @@ -219,10 +200,27 @@ function useAppleCalendarSelection() {
}
return result.data;
},
onSuccess: (calendars) => {
store?.transaction(() => {
for (const cal of calendars) {
setCalendarRow(cal);
onSuccess: (incomingCalendars) => {
if (!store || !user_id) return;

store.transaction(() => {
for (const cal of incomingCalendars) {
const existingRowId = findCalendarByTrackingId(store, cal.id);
const rowId = existingRowId ?? crypto.randomUUID();
const existing = existingRowId
? store.getRow("calendars", existingRowId)
: null;

store.setRow("calendars", rowId, {
user_id,
created_at: existing?.created_at || new Date().toISOString(),
tracking_id_calendar: cal.id,
name: cal.title,
enabled: existing?.enabled ?? false,
provider: "apple",
source: cal.source.title,
color: colorToCSS(cal.color),
});
}
});
},
Expand Down
7 changes: 5 additions & 2 deletions apps/desktop/src/hooks/useAutoCloser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@ export function useAutoCloser(
outside?: boolean;
},
) {
const ref = useRef<HTMLDivElement>(null!);
const ref = useRef<HTMLDivElement | null>(null);

const handleClose = useCallback(() => {
onClose();
}, [onClose]);

useHotkeys("esc", handleClose, { enabled: esc }, [handleClose]);
useOnClickOutside(ref, outside ? handleClose : () => {});
useOnClickOutside(
ref as React.RefObject<HTMLDivElement>,
outside ? handleClose : () => {},
);

return ref;
}
13 changes: 12 additions & 1 deletion apps/desktop/src/services/apple-calendar/ctx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,24 @@ export interface Ctx {
from: Date;
to: Date;
calendarIds: Set<string>;
calendarTrackingIdToId: Map<string, string>;
}

export function createCtx(store: Store, queries: Queries<Schemas>): Ctx | null {
const resultTable = queries.getResultTable(QUERIES.enabledAppleCalendars);

const calendarIds = new Set(Object.keys(resultTable));
const calendarTrackingIdToId = new Map<string, string>();

for (const calendarId of calendarIds) {
const calendar = store.getRow("calendars", calendarId);
const trackingId = calendar?.tracking_id_calendar as string | undefined;
if (trackingId) {
calendarTrackingIdToId.set(trackingId, calendarId);
}
}

if (calendarIds.size === 0) {
if (calendarTrackingIdToId.size === 0) {
return null;
}

Expand All @@ -32,6 +42,7 @@ export function createCtx(store: Store, queries: Queries<Schemas>): Ctx | null {
from,
to,
calendarIds,
calendarTrackingIdToId,
};
}

Expand Down
5 changes: 3 additions & 2 deletions apps/desktop/src/services/apple-calendar/fetch/existing.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { Ctx } from "../ctx";
import type { ExistingEvent } from "./types";

export function fetchExistingEvents(ctx: Ctx): Array<ExistingEvent> {
const events: Array<ExistingEvent> = [];
export function fetchExistingEvents(ctx: Ctx): ExistingEvent[] {
const events: ExistingEvent[] = [];

ctx.store.forEachRow("events", (rowId, _forEachCell) => {
const event = ctx.store.getRow("events", rowId);
Expand All @@ -20,6 +20,7 @@ export function fetchExistingEvents(ctx: Ctx): Array<ExistingEvent> {
if (eventDate >= ctx.from && eventDate <= ctx.to) {
events.push({
id: rowId,
tracking_id_event: event.tracking_id_event as string | undefined,
user_id: event.user_id as string | undefined,
created_at: event.created_at as string | undefined,
calendar_id: calendarId,
Expand Down
14 changes: 7 additions & 7 deletions apps/desktop/src/services/apple-calendar/fetch/incoming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import type { EventParticipant } from "@hypr/store";
import type { Ctx } from "../ctx";
import type { IncomingEvent } from "./types";

export async function fetchIncomingEvents(
ctx: Ctx,
): Promise<Array<IncomingEvent>> {
export async function fetchIncomingEvents(ctx: Ctx): Promise<IncomingEvent[]> {
const trackingIds = Array.from(ctx.calendarTrackingIdToId.keys());

const results = await Promise.all(
Array.from(ctx.calendarIds).map(async (calendarId) => {
trackingIds.map(async (trackingId) => {
const result = await appleCalendarCommands.listEvents({
calendar_tracking_id: calendarId,
calendar_tracking_id: trackingId,
from: ctx.from.toISOString(),
to: ctx.to.toISOString(),
});
Expand Down Expand Up @@ -45,8 +45,8 @@ async function normalizeAppleEvent(event: AppleEvent): Promise<IncomingEvent> {
}

return {
id: event.event_identifier,
calendar_id: event.calendar.id,
tracking_id_event: event.event_identifier,
tracking_id_calendar: event.calendar.id,
title: event.title,
started_at: event.start_date,
ended_at: event.end_date,
Expand Down
20 changes: 15 additions & 5 deletions apps/desktop/src/services/apple-calendar/fetch/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import { EventStorage } from "@hypr/store";

type EventBaseForSync = { id: string };
export type IncomingEvent = {
tracking_id_event: string;
tracking_id_calendar: string;
title?: string;
started_at?: string;
ended_at?: string;
location?: string;
meeting_link?: string;
description?: string;
participants?: string;
};

export type IncomingEvent = EventBaseForSync &
Omit<EventStorage, "user_id" | "created_at">;

export type ExistingEvent = EventBaseForSync & EventStorage;
export type ExistingEvent = {
id: string;
tracking_id_event?: string;
} & EventStorage;
16 changes: 13 additions & 3 deletions apps/desktop/src/services/apple-calendar/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import type { Queries } from "tinybase/with-schemas";
import type { Schemas, Store } from "../../store/tinybase/main";
import { createCtx } from "./ctx";
import { fetchExistingEvents, fetchIncomingEvents } from "./fetch";
import { execute, sync } from "./process";
import {
executeForEventsSync,
executeForParticipantsSync,
syncEvents,
syncParticipants,
} from "./process";

export const CALENDAR_SYNC_TASK_ID = "calendarSync";

Expand All @@ -26,6 +31,11 @@ async function run(store: Store, queries: Queries<Schemas>) {
const incoming = await fetchIncomingEvents(ctx);
const existing = fetchExistingEvents(ctx);

const out = sync(ctx, { incoming, existing });
execute(ctx.store, out);
const out = syncEvents(ctx, { incoming, existing });
const { addedEventIds } = executeForEventsSync(ctx, out);

const participantsOut = syncParticipants(ctx, {
eventIds: [...out.toUpdate.map((e) => e.id), ...addedEventIds],
});
executeForParticipantsSync(ctx, participantsOut);
}
Loading