feat(p8): /v1/calendar REST + kernel-client methods + @insignia/iios-meeting-web
Task 8.6: CalendarController exposes schedule/request(+fromCallback/fromClaim)/ list/get/consent/transcript/summarize/action-items/providers(+sync) (session-auth). kernel-client RestClient gains scheduleMeeting/requestMeeting/listMeetings/ getMeeting/setConsent/generateTranscript/summarizeMeeting/listActionItems/ connect+syncCalendarProvider + Meeting/MeetingParticipant/MeetingActionItem types. New @insignia/iios-meeting-web (MeetingProvider + useMeetings/useMeeting/useSchedule/ useConsent/useSummarize/useActionItems). Boundary: meeting-web -> contracts + kernel-client (fails on meeting-web->service). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
export { MeetingProvider, useMeetings, useMeeting, useSchedule, useConsent, useSummarize, useActionItems } from './react';
|
||||
export type { Meeting, MeetingParticipant, MeetingActionItem } from '@insignia/iios-kernel-client';
|
||||
@@ -0,0 +1,97 @@
|
||||
import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
||||
import { RestClient, type Meeting, type MeetingActionItem } from '@insignia/iios-kernel-client';
|
||||
|
||||
const MeetingContext = createContext<RestClient | null>(null);
|
||||
|
||||
export function MeetingProvider({
|
||||
serviceUrl,
|
||||
token,
|
||||
children,
|
||||
}: {
|
||||
serviceUrl: string;
|
||||
token: string;
|
||||
children: React.ReactNode;
|
||||
}): React.ReactElement {
|
||||
const client = useMemo(() => new RestClient({ serviceUrl, token }), [serviceUrl, token]);
|
||||
return <MeetingContext.Provider value={client}>{children}</MeetingContext.Provider>;
|
||||
}
|
||||
|
||||
function useClient(): RestClient {
|
||||
const c = useContext(MeetingContext);
|
||||
if (!c) throw new Error('meeting hooks must be used within <MeetingProvider>');
|
||||
return c;
|
||||
}
|
||||
|
||||
export function useMeetings(opts?: { pollMs?: number }): { meetings: Meeting[]; refresh: () => Promise<void> } {
|
||||
const client = useClient();
|
||||
const [meetings, setMeetings] = useState<Meeting[]>([]);
|
||||
const refresh = useCallback(async () => {
|
||||
try {
|
||||
setMeetings(await client.listMeetings());
|
||||
} catch {
|
||||
/* transient */
|
||||
}
|
||||
}, [client]);
|
||||
useEffect(() => {
|
||||
void refresh();
|
||||
if (!opts?.pollMs) return;
|
||||
const t = setInterval(() => void refresh(), opts.pollMs);
|
||||
return () => clearInterval(t);
|
||||
}, [refresh, opts?.pollMs]);
|
||||
return { meetings, refresh };
|
||||
}
|
||||
|
||||
export function useMeeting(id: string | null): { meeting: Meeting | null; refresh: () => Promise<void> } {
|
||||
const client = useClient();
|
||||
const [meeting, setMeeting] = useState<Meeting | null>(null);
|
||||
const refresh = useCallback(async () => {
|
||||
if (!id) return setMeeting(null);
|
||||
try {
|
||||
setMeeting(await client.getMeeting(id));
|
||||
} catch {
|
||||
/* transient */
|
||||
}
|
||||
}, [client, id]);
|
||||
useEffect(() => {
|
||||
void refresh();
|
||||
}, [refresh]);
|
||||
return { meeting, refresh };
|
||||
}
|
||||
|
||||
export function useSchedule(): (input: Parameters<RestClient['scheduleMeeting']>[0]) => Promise<Meeting> {
|
||||
const client = useClient();
|
||||
return (input) => client.scheduleMeeting(input);
|
||||
}
|
||||
|
||||
export function useConsent(): {
|
||||
setConsent: (meetingId: string, actorRefId: string, status: string) => Promise<unknown>;
|
||||
generateTranscript: (meetingId: string) => Promise<unknown>;
|
||||
} {
|
||||
const client = useClient();
|
||||
return {
|
||||
setConsent: (meetingId, actorRefId, status) => client.setConsent(meetingId, actorRefId, status),
|
||||
generateTranscript: (meetingId) => client.generateTranscript(meetingId),
|
||||
};
|
||||
}
|
||||
|
||||
export function useSummarize(): (meetingId: string) => Promise<Meeting> {
|
||||
const client = useClient();
|
||||
return (meetingId) => client.summarizeMeeting(meetingId);
|
||||
}
|
||||
|
||||
export function useActionItems(meetingId: string | null): { actionItems: MeetingActionItem[]; refresh: () => Promise<void> } {
|
||||
const client = useClient();
|
||||
const [actionItems, setActionItems] = useState<MeetingActionItem[]>([]);
|
||||
const refresh = useCallback(async () => {
|
||||
if (!meetingId) return setActionItems([]);
|
||||
try {
|
||||
setActionItems(await client.listActionItems(meetingId));
|
||||
} catch {
|
||||
/* transient */
|
||||
}
|
||||
}, [client, meetingId]);
|
||||
useEffect(() => {
|
||||
void refresh();
|
||||
}, [refresh]);
|
||||
return { actionItems, refresh };
|
||||
}
|
||||
Reference in New Issue
Block a user