mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-20 20:29:06 +00:00
slop review
This commit is contained in:
@@ -12,6 +12,7 @@ import { DomainContext } from "../domainContext";
|
||||
import { useRecordingConsent } from "../recordingConsentContext";
|
||||
import useSessionAccessToken from "../lib/useSessionAccessToken";
|
||||
import useSessionUser from "../lib/useSessionUser";
|
||||
import useApi from "../lib/useApi";
|
||||
|
||||
export type RoomDetails = {
|
||||
params: {
|
||||
@@ -31,6 +32,7 @@ export default function Room(details: RoomDetails) {
|
||||
const { api_url } = useContext(DomainContext);
|
||||
const { accessToken } = useSessionAccessToken();
|
||||
const { id: userId } = useSessionUser();
|
||||
const api = useApi();
|
||||
|
||||
|
||||
const roomUrl = meeting?.response?.host_room_url
|
||||
@@ -43,38 +45,25 @@ export default function Room(details: RoomDetails) {
|
||||
router.push("/browse");
|
||||
}, [router]);
|
||||
|
||||
// TODO hook
|
||||
const handleConsent = useCallback(async (meetingId: string, given: boolean) => {
|
||||
if (!api) return;
|
||||
|
||||
setShowConsentDialog(false);
|
||||
setConsentLoading(true);
|
||||
|
||||
try {
|
||||
const requestBody = {
|
||||
consent_given: given
|
||||
};
|
||||
|
||||
// TODO generated API
|
||||
const response = await fetch(`${api_url}/v1/meetings/${meetingId}/consent`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(accessToken && { 'Authorization': `Bearer ${accessToken}` })
|
||||
},
|
||||
body: JSON.stringify(requestBody),
|
||||
await api.v1MeetingAudioConsent({
|
||||
meetingId,
|
||||
requestBody: { consent_given: given }
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
touch(meetingId);
|
||||
} else {
|
||||
console.error('Failed to submit consent');
|
||||
}
|
||||
|
||||
touch(meetingId);
|
||||
} catch (error) {
|
||||
console.error('Error submitting consent:', error);
|
||||
} finally {
|
||||
setConsentLoading(false);
|
||||
}
|
||||
}, [api_url, accessToken, touch]);
|
||||
}, [api, touch]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -548,6 +548,18 @@ export const $Meeting = {
|
||||
title: "Meeting",
|
||||
} as const;
|
||||
|
||||
export const $MeetingConsentRequest = {
|
||||
properties: {
|
||||
consent_given: {
|
||||
type: "boolean",
|
||||
title: "Consent Given",
|
||||
},
|
||||
},
|
||||
type: "object",
|
||||
required: ["consent_given"],
|
||||
title: "MeetingConsentRequest",
|
||||
} as const;
|
||||
|
||||
export const $Page_GetTranscript_ = {
|
||||
properties: {
|
||||
items: {
|
||||
@@ -1166,6 +1178,35 @@ export const $ValidationError = {
|
||||
title: "ValidationError",
|
||||
} as const;
|
||||
|
||||
export const $WherebyWebhookEvent = {
|
||||
properties: {
|
||||
apiVersion: {
|
||||
type: "string",
|
||||
title: "Apiversion",
|
||||
},
|
||||
id: {
|
||||
type: "string",
|
||||
title: "Id",
|
||||
},
|
||||
createdAt: {
|
||||
type: "string",
|
||||
format: "date-time",
|
||||
title: "Createdat",
|
||||
},
|
||||
type: {
|
||||
type: "string",
|
||||
title: "Type",
|
||||
},
|
||||
data: {
|
||||
type: "object",
|
||||
title: "Data",
|
||||
},
|
||||
},
|
||||
type: "object",
|
||||
required: ["apiVersion", "id", "createdAt", "type", "data"],
|
||||
title: "WherebyWebhookEvent",
|
||||
} as const;
|
||||
|
||||
export const $Word = {
|
||||
properties: {
|
||||
text: {
|
||||
|
||||
@@ -4,6 +4,8 @@ import type { CancelablePromise } from "./core/CancelablePromise";
|
||||
import type { BaseHttpRequest } from "./core/BaseHttpRequest";
|
||||
import type {
|
||||
MetricsResponse,
|
||||
V1MeetingAudioConsentData,
|
||||
V1MeetingAudioConsentResponse,
|
||||
V1RoomsListData,
|
||||
V1RoomsListResponse,
|
||||
V1RoomsCreateData,
|
||||
@@ -64,6 +66,8 @@ import type {
|
||||
V1ZulipGetStreamsResponse,
|
||||
V1ZulipGetTopicsData,
|
||||
V1ZulipGetTopicsResponse,
|
||||
V1WherebyWebhookData,
|
||||
V1WherebyWebhookResponse,
|
||||
} from "./types.gen";
|
||||
|
||||
export class DefaultService {
|
||||
@@ -82,6 +86,31 @@ export class DefaultService {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Meeting Audio Consent
|
||||
* @param data The data for the request.
|
||||
* @param data.meetingId
|
||||
* @param data.requestBody
|
||||
* @returns unknown Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public v1MeetingAudioConsent(
|
||||
data: V1MeetingAudioConsentData,
|
||||
): CancelablePromise<V1MeetingAudioConsentResponse> {
|
||||
return this.httpRequest.request({
|
||||
method: "POST",
|
||||
url: "/v1/meetings/{meeting_id}/consent",
|
||||
path: {
|
||||
meeting_id: data.meetingId,
|
||||
},
|
||||
body: data.requestBody,
|
||||
mediaType: "application/json",
|
||||
errors: {
|
||||
422: "Validation Error",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Rooms List
|
||||
* @param data The data for the request.
|
||||
@@ -807,4 +836,25 @@ export class DefaultService {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Whereby Webhook
|
||||
* @param data The data for the request.
|
||||
* @param data.requestBody
|
||||
* @returns unknown Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public v1WherebyWebhook(
|
||||
data: V1WherebyWebhookData,
|
||||
): CancelablePromise<V1WherebyWebhookResponse> {
|
||||
return this.httpRequest.request({
|
||||
method: "POST",
|
||||
url: "/v1/whereby",
|
||||
body: data.requestBody,
|
||||
mediaType: "application/json",
|
||||
errors: {
|
||||
422: "Validation Error",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +109,10 @@ export type Meeting = {
|
||||
end_date: string;
|
||||
};
|
||||
|
||||
export type MeetingConsentRequest = {
|
||||
consent_given: boolean;
|
||||
};
|
||||
|
||||
export type Page_GetTranscript_ = {
|
||||
items: Array<GetTranscript>;
|
||||
total: number;
|
||||
@@ -229,6 +233,16 @@ export type ValidationError = {
|
||||
type: string;
|
||||
};
|
||||
|
||||
export type WherebyWebhookEvent = {
|
||||
apiVersion: string;
|
||||
id: string;
|
||||
createdAt: string;
|
||||
type: string;
|
||||
data: {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
};
|
||||
|
||||
export type Word = {
|
||||
text: string;
|
||||
start: number;
|
||||
@@ -238,6 +252,13 @@ export type Word = {
|
||||
|
||||
export type MetricsResponse = unknown;
|
||||
|
||||
export type V1MeetingAudioConsentData = {
|
||||
meetingId: string;
|
||||
requestBody: MeetingConsentRequest;
|
||||
};
|
||||
|
||||
export type V1MeetingAudioConsentResponse = unknown;
|
||||
|
||||
export type V1RoomsListData = {
|
||||
/**
|
||||
* Page number
|
||||
@@ -454,6 +475,12 @@ export type V1ZulipGetTopicsData = {
|
||||
|
||||
export type V1ZulipGetTopicsResponse = Array<Topic>;
|
||||
|
||||
export type V1WherebyWebhookData = {
|
||||
requestBody: WherebyWebhookEvent;
|
||||
};
|
||||
|
||||
export type V1WherebyWebhookResponse = unknown;
|
||||
|
||||
export type $OpenApiTs = {
|
||||
"/metrics": {
|
||||
get: {
|
||||
@@ -465,6 +492,21 @@ export type $OpenApiTs = {
|
||||
};
|
||||
};
|
||||
};
|
||||
"/v1/meetings/{meeting_id}/consent": {
|
||||
post: {
|
||||
req: V1MeetingAudioConsentData;
|
||||
res: {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: unknown;
|
||||
/**
|
||||
* Validation Error
|
||||
*/
|
||||
422: HTTPValidationError;
|
||||
};
|
||||
};
|
||||
};
|
||||
"/v1/rooms": {
|
||||
get: {
|
||||
req: V1RoomsListData;
|
||||
@@ -902,4 +944,19 @@ export type $OpenApiTs = {
|
||||
};
|
||||
};
|
||||
};
|
||||
"/v1/whereby": {
|
||||
post: {
|
||||
req: V1WherebyWebhookData;
|
||||
res: {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: unknown;
|
||||
/**
|
||||
* Validation Error
|
||||
*/
|
||||
422: HTTPValidationError;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -29,17 +29,20 @@ interface RecordingConsentProviderProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const LOCAL_STORAGE_KEY = "recording_consent_meetings";
|
||||
|
||||
export const RecordingConsentProvider: React.FC<RecordingConsentProviderProps> = ({ children }) => {
|
||||
const [state, setState] = useState<ConsentContextState>({ ready: false });
|
||||
|
||||
const safeWriteToStorage = (meetingIds: string[]): void => {
|
||||
try {
|
||||
localStorage.setItem("recording_consent_meetings", JSON.stringify(meetingIds));
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(meetingIds));
|
||||
} catch (error) {
|
||||
console.error("Failed to save consent data to localStorage:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// writes to local storage and to the state of context both
|
||||
const touch = (meetingId: string): void => {
|
||||
|
||||
if (!state.ready) {
|
||||
@@ -47,13 +50,14 @@ export const RecordingConsentProvider: React.FC<RecordingConsentProviderProps> =
|
||||
return;
|
||||
}
|
||||
|
||||
// Update context state (always works)
|
||||
const newSet = new Set([...state.consentAnsweredForMeetings, meetingId]);
|
||||
|
||||
// has success regardless local storage write success: we don't handle that
|
||||
// and don't want to crash anything with just consent functionality
|
||||
const newSet = state.consentAnsweredForMeetings.has(meetingId) ?
|
||||
state.consentAnsweredForMeetings :
|
||||
new Set([...state.consentAnsweredForMeetings, meetingId]);
|
||||
// note: preserves the set insertion order
|
||||
const array = Array.from(newSet).slice(-5); // Keep latest 5
|
||||
safeWriteToStorage(array);
|
||||
|
||||
// Update state regardless of storage success
|
||||
setState({ ready: true, consentAnsweredForMeetings: newSet });
|
||||
};
|
||||
|
||||
@@ -62,10 +66,10 @@ export const RecordingConsentProvider: React.FC<RecordingConsentProviderProps> =
|
||||
return state.consentAnsweredForMeetings.has(meetingId);
|
||||
};
|
||||
|
||||
// Initialize from localStorage on mount (client-side only)
|
||||
// initialize on mount
|
||||
useEffect(() => {
|
||||
try {
|
||||
const stored = localStorage.getItem("recording_consent_meetings");
|
||||
const stored = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
if (!stored) {
|
||||
setState({ ready: true, consentAnsweredForMeetings: new Set() });
|
||||
return;
|
||||
@@ -77,10 +81,12 @@ export const RecordingConsentProvider: React.FC<RecordingConsentProviderProps> =
|
||||
setState({ ready: true, consentAnsweredForMeetings: new Set() });
|
||||
return;
|
||||
}
|
||||
|
||||
const consentAnsweredForMeetings = new Set(parsed.filter(id => typeof id === 'string'));
|
||||
|
||||
// pre-historic way of parsing!
|
||||
const consentAnsweredForMeetings = new Set(parsed.filter(id => !!id && typeof id === 'string'));
|
||||
setState({ ready: true, consentAnsweredForMeetings });
|
||||
} catch (error) {
|
||||
// we don't want to fail the page here; the component is not essential.
|
||||
console.error("Failed to parse consent data from localStorage:", error);
|
||||
setState({ ready: true, consentAnsweredForMeetings: new Set() });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user