@ai-matrx/meet 0.7.78 → 0.7.79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/index.cjs +219 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +120 -1
- package/dist/index.d.ts +120 -1
- package/dist/index.js +219 -4
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +478 -203
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +4 -3
- package/dist/react.d.ts +4 -3
- package/dist/react.js +373 -98
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/react.cjs
CHANGED
|
@@ -83,6 +83,7 @@ __export(react_exports, {
|
|
|
83
83
|
LockIcon: () => LockIcon,
|
|
84
84
|
MEETING_INVITE_KIND: () => MEETING_INVITE_KIND,
|
|
85
85
|
MEETING_INVITE_VERSION: () => MEETING_INVITE_VERSION,
|
|
86
|
+
MEETING_RECORD_GRACE_MS: () => MEETING_RECORD_GRACE_MS,
|
|
86
87
|
MEET_ANSWER_CONTEXT_EVENT: () => MEET_ANSWER_CONTEXT_EVENT,
|
|
87
88
|
MEET_ANSWER_EVENTS: () => MEET_ANSWER_EVENTS,
|
|
88
89
|
MEET_EVENTS: () => MEET_EVENTS,
|
|
@@ -160,6 +161,7 @@ __export(react_exports, {
|
|
|
160
161
|
asParticipantIdentity: () => asParticipantIdentity,
|
|
161
162
|
asRoomName: () => asRoomName,
|
|
162
163
|
asUserId: () => asUserId,
|
|
164
|
+
assembleMeetingRecord: () => assembleMeetingRecord,
|
|
163
165
|
assignedRoom: () => assignedRoom,
|
|
164
166
|
attendanceCsv: () => attendanceCsv,
|
|
165
167
|
attendanceReport: () => attendanceReport,
|
|
@@ -189,6 +191,7 @@ __export(react_exports, {
|
|
|
189
191
|
createMeetRepository: () => createMeetRepository,
|
|
190
192
|
createMeetStore: () => createMeetStore,
|
|
191
193
|
createMeetingInviteHandler: () => createMeetingInviteHandler,
|
|
194
|
+
createMeetingRecordCache: () => createMeetingRecordCache,
|
|
192
195
|
createMeetingSession: () => createMeetingSession,
|
|
193
196
|
createMemoryDeviceStorage: () => createMemoryDeviceStorage,
|
|
194
197
|
createRecordingController: () => createRecordingController,
|
|
@@ -223,12 +226,14 @@ __export(react_exports, {
|
|
|
223
226
|
loadMeetingActivities: () => loadMeetingActivities,
|
|
224
227
|
loadMeetingChat: () => loadMeetingChat,
|
|
225
228
|
loadMeetingRecord: () => loadMeetingRecord,
|
|
229
|
+
loadMeetingRecordParts: () => loadMeetingRecordParts,
|
|
226
230
|
mapConnectionState: () => mapConnectionState,
|
|
227
231
|
mapQuality: () => mapQuality,
|
|
228
232
|
meetingInviteAction: () => meetingInviteAction,
|
|
229
233
|
meetingLength: () => meetingLength,
|
|
230
234
|
meetingLink: () => meetingLink,
|
|
231
235
|
meetingPath: () => meetingPath,
|
|
236
|
+
meetingRecordCache: () => meetingRecordCache,
|
|
232
237
|
meetingSlug: () => meetingSlug,
|
|
233
238
|
meetingTopic: () => meetingTopic,
|
|
234
239
|
meetingWhen: () => meetingWhen,
|
|
@@ -2205,13 +2210,13 @@ function mergeCaption(list, caption) {
|
|
|
2205
2210
|
return list.map((entry, position) => position === index ? caption : entry);
|
|
2206
2211
|
}
|
|
2207
2212
|
function mergeRecord(list, record) {
|
|
2208
|
-
const
|
|
2209
|
-
if (
|
|
2210
|
-
const existing = list[
|
|
2213
|
+
const byId2 = list.findIndex((entry) => entry.source === "record" && entry.id === record.id);
|
|
2214
|
+
if (byId2 !== -1) {
|
|
2215
|
+
const existing = list[byId2];
|
|
2211
2216
|
if (existing !== void 0 && existing.text === record.text && existing.final === record.final) {
|
|
2212
2217
|
return list;
|
|
2213
2218
|
}
|
|
2214
|
-
return list.map((entry, position) => position ===
|
|
2219
|
+
return list.map((entry, position) => position === byId2 ? record : entry);
|
|
2215
2220
|
}
|
|
2216
2221
|
const captionIndex = list.findIndex((entry) => supersedes(record, entry));
|
|
2217
2222
|
if (captionIndex === -1) return [...list, record];
|
|
@@ -5786,49 +5791,7 @@ function useLocalUserId() {
|
|
|
5786
5791
|
|
|
5787
5792
|
// src/react/hooks.ts
|
|
5788
5793
|
var import_react3 = require("react");
|
|
5789
|
-
|
|
5790
|
-
// src/core/layout.ts
|
|
5791
|
-
var DEFAULT_PAGE_SIZE = 12;
|
|
5792
|
-
function orderParticipants(participants, activeSpeakers) {
|
|
5793
|
-
const speakerRank = /* @__PURE__ */ new Map();
|
|
5794
|
-
activeSpeakers.forEach((identity, index) => speakerRank.set(identity, index));
|
|
5795
|
-
return [...participants].sort((a, b) => {
|
|
5796
|
-
const speakerA = speakerRank.get(a.identity) ?? Number.MAX_SAFE_INTEGER;
|
|
5797
|
-
const speakerB = speakerRank.get(b.identity) ?? Number.MAX_SAFE_INTEGER;
|
|
5798
|
-
if (speakerA !== speakerB) return speakerA - speakerB;
|
|
5799
|
-
if (a.handRaised !== b.handRaised) return a.handRaised ? -1 : 1;
|
|
5800
|
-
if (a.cameraEnabled !== b.cameraEnabled) return a.cameraEnabled ? -1 : 1;
|
|
5801
|
-
if (a.joinedAt !== b.joinedAt) return a.joinedAt < b.joinedAt ? -1 : 1;
|
|
5802
|
-
return a.identity < b.identity ? -1 : 1;
|
|
5803
|
-
});
|
|
5804
|
-
}
|
|
5805
|
-
function computeStage(args) {
|
|
5806
|
-
const pageSize = Math.max(1, args.pageSize ?? DEFAULT_PAGE_SIZE);
|
|
5807
|
-
const ordered = orderParticipants(args.participants, args.activeSpeakers);
|
|
5808
|
-
const sharer = ordered.find((participant) => participant.screenSharing) ?? null;
|
|
5809
|
-
const pinnedParticipant = args.pinned === null ? null : ordered.find((participant) => participant.identity === args.pinned) ?? null;
|
|
5810
|
-
const spotlit = args.spotlight == null ? null : ordered.find((participant) => participant.identity === args.spotlight) ?? null;
|
|
5811
|
-
const feature = sharer !== null ? sharer : pinnedParticipant !== null && args.layout !== "grid" ? pinnedParticipant : spotlit !== null ? spotlit : args.layout === "grid" ? null : ordered[0] ?? null;
|
|
5812
|
-
const rest = feature === null ? ordered : ordered.filter((participant) => participant.identity !== feature.identity);
|
|
5813
|
-
const pageCount = Math.max(1, Math.ceil(rest.length / pageSize));
|
|
5814
|
-
const page = Math.min(Math.max(0, args.page ?? 0), pageCount - 1);
|
|
5815
|
-
const tiles = rest.slice(page * pageSize, page * pageSize + pageSize);
|
|
5816
|
-
return {
|
|
5817
|
-
feature,
|
|
5818
|
-
tiles,
|
|
5819
|
-
overflow: rest.length - tiles.length,
|
|
5820
|
-
page,
|
|
5821
|
-
pageCount,
|
|
5822
|
-
presenting: sharer !== null
|
|
5823
|
-
};
|
|
5824
|
-
}
|
|
5825
|
-
function gridColumns(count2) {
|
|
5826
|
-
if (count2 <= 1) return 1;
|
|
5827
|
-
if (count2 <= 4) return 2;
|
|
5828
|
-
if (count2 <= 9) return 3;
|
|
5829
|
-
if (count2 <= 16) return 4;
|
|
5830
|
-
return 5;
|
|
5831
|
-
}
|
|
5794
|
+
var import_react4 = require("@ai-matrx/realtime/react");
|
|
5832
5795
|
|
|
5833
5796
|
// src/core/record.ts
|
|
5834
5797
|
var import_format = require("@ai-matrx/kit/format");
|
|
@@ -5852,6 +5815,9 @@ function restrictionFor(part, error) {
|
|
|
5852
5815
|
};
|
|
5853
5816
|
}
|
|
5854
5817
|
async function loadMeetingRecord(repository, meetingId, meeting, reader = { userId: null }) {
|
|
5818
|
+
return assembleMeetingRecord(meeting, await loadMeetingRecordParts(repository, meetingId, reader));
|
|
5819
|
+
}
|
|
5820
|
+
async function loadMeetingRecordParts(repository, meetingId, reader = { userId: null }) {
|
|
5855
5821
|
const restrictions = [];
|
|
5856
5822
|
async function attempt(part, run, empty) {
|
|
5857
5823
|
if (reader.userId === null) {
|
|
@@ -5879,6 +5845,10 @@ async function loadMeetingRecord(repository, meetingId, meeting, reader = { user
|
|
|
5879
5845
|
[]
|
|
5880
5846
|
)
|
|
5881
5847
|
]);
|
|
5848
|
+
return { attendees, notes, transcript, recordings, restrictions };
|
|
5849
|
+
}
|
|
5850
|
+
function assembleMeetingRecord(meeting, parts) {
|
|
5851
|
+
const { attendees, notes, transcript, recordings, restrictions } = parts;
|
|
5882
5852
|
return {
|
|
5883
5853
|
meeting,
|
|
5884
5854
|
attendees,
|
|
@@ -6224,6 +6194,253 @@ async function setGuestRecordAccess(args) {
|
|
|
6224
6194
|
}
|
|
6225
6195
|
var GUEST_RECORD_NOT_SHARED = NOT_SHARED;
|
|
6226
6196
|
|
|
6197
|
+
// src/core/record-cache.ts
|
|
6198
|
+
var MEETING_RECORD_GRACE_MS = 6e4;
|
|
6199
|
+
var INITIAL = { loading: true, record: null, failure: null };
|
|
6200
|
+
function upsert2(rows, row, removedId, order) {
|
|
6201
|
+
const id = row?.id ?? removedId;
|
|
6202
|
+
if (id === void 0) return rows;
|
|
6203
|
+
const rest = rows.filter((existing) => existing.id !== id);
|
|
6204
|
+
return row === null ? rest : [...rest, row].sort(order);
|
|
6205
|
+
}
|
|
6206
|
+
var byId = (a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
|
|
6207
|
+
var ascending = (a, b) => a === b ? 0 : a === null ? 1 : b === null ? -1 : a < b ? -1 : 1;
|
|
6208
|
+
function createMeetingRecordCache(options = {}) {
|
|
6209
|
+
const graceMs = options.graceMs ?? MEETING_RECORD_GRACE_MS;
|
|
6210
|
+
const entries = /* @__PURE__ */ new Map();
|
|
6211
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
6212
|
+
const notify = () => {
|
|
6213
|
+
for (const listener of listeners) listener();
|
|
6214
|
+
};
|
|
6215
|
+
const entryOf = (key) => {
|
|
6216
|
+
let entry = entries.get(key);
|
|
6217
|
+
if (!entry) {
|
|
6218
|
+
entry = {
|
|
6219
|
+
state: INITIAL,
|
|
6220
|
+
meeting: null,
|
|
6221
|
+
parts: null,
|
|
6222
|
+
fresh: false,
|
|
6223
|
+
seq: 0,
|
|
6224
|
+
inflight: null,
|
|
6225
|
+
holders: 0,
|
|
6226
|
+
close: null,
|
|
6227
|
+
owner: null,
|
|
6228
|
+
grace: null
|
|
6229
|
+
};
|
|
6230
|
+
entries.set(key, entry);
|
|
6231
|
+
}
|
|
6232
|
+
return entry;
|
|
6233
|
+
};
|
|
6234
|
+
const assemble = (entry) => {
|
|
6235
|
+
if (entry.meeting === null || entry.parts === null) return;
|
|
6236
|
+
entry.state = { loading: false, failure: null, record: assembleMeetingRecord(entry.meeting, entry.parts) };
|
|
6237
|
+
notify();
|
|
6238
|
+
};
|
|
6239
|
+
return {
|
|
6240
|
+
state: (key) => key === null ? INITIAL : entries.get(key)?.state ?? INITIAL,
|
|
6241
|
+
subscribe(listener) {
|
|
6242
|
+
listeners.add(listener);
|
|
6243
|
+
return () => {
|
|
6244
|
+
listeners.delete(listener);
|
|
6245
|
+
};
|
|
6246
|
+
},
|
|
6247
|
+
ensure(key, read, { force = false } = {}) {
|
|
6248
|
+
const entry = entryOf(key);
|
|
6249
|
+
if (!force) {
|
|
6250
|
+
if (entry.inflight !== null) return entry.inflight;
|
|
6251
|
+
if (entry.fresh) return Promise.resolve();
|
|
6252
|
+
}
|
|
6253
|
+
const seq = ++entry.seq;
|
|
6254
|
+
if (entry.state.failure !== null) {
|
|
6255
|
+
entry.state = { ...entry.state, loading: true, failure: null };
|
|
6256
|
+
notify();
|
|
6257
|
+
}
|
|
6258
|
+
const request = read().then(
|
|
6259
|
+
(answer) => {
|
|
6260
|
+
if (seq !== entry.seq) return;
|
|
6261
|
+
entry.fresh = true;
|
|
6262
|
+
if (answer.kind === "parts") {
|
|
6263
|
+
entry.meeting = answer.meeting;
|
|
6264
|
+
entry.parts = answer.parts;
|
|
6265
|
+
assemble(entry);
|
|
6266
|
+
} else {
|
|
6267
|
+
entry.meeting = answer.bundle.meeting;
|
|
6268
|
+
entry.parts = null;
|
|
6269
|
+
entry.state = { loading: false, failure: null, record: answer.bundle };
|
|
6270
|
+
notify();
|
|
6271
|
+
}
|
|
6272
|
+
},
|
|
6273
|
+
(thrown) => {
|
|
6274
|
+
if (seq !== entry.seq) return;
|
|
6275
|
+
entry.fresh = false;
|
|
6276
|
+
entry.state = {
|
|
6277
|
+
loading: false,
|
|
6278
|
+
record: entry.state.record,
|
|
6279
|
+
failure: {
|
|
6280
|
+
message: thrown?.message ?? String(thrown),
|
|
6281
|
+
remedy: thrown?.remedy ?? "The meeting record could not be read. Reload the page; nothing was changed."
|
|
6282
|
+
}
|
|
6283
|
+
};
|
|
6284
|
+
notify();
|
|
6285
|
+
}
|
|
6286
|
+
);
|
|
6287
|
+
const tracked = request.finally(() => {
|
|
6288
|
+
if (entry.inflight === tracked) entry.inflight = null;
|
|
6289
|
+
});
|
|
6290
|
+
entry.inflight = tracked;
|
|
6291
|
+
return tracked;
|
|
6292
|
+
},
|
|
6293
|
+
setMeeting(key, meeting) {
|
|
6294
|
+
const entry = entries.get(key);
|
|
6295
|
+
if (!entry || entry.meeting === meeting) return;
|
|
6296
|
+
if (entry.parts !== null) {
|
|
6297
|
+
entry.meeting = meeting;
|
|
6298
|
+
assemble(entry);
|
|
6299
|
+
} else if (entry.state.record !== null) {
|
|
6300
|
+
entry.meeting = meeting;
|
|
6301
|
+
entry.state = { ...entry.state, record: { ...entry.state.record, meeting } };
|
|
6302
|
+
notify();
|
|
6303
|
+
}
|
|
6304
|
+
},
|
|
6305
|
+
apply(key, change) {
|
|
6306
|
+
const entry = entries.get(key);
|
|
6307
|
+
const parts = entry?.parts;
|
|
6308
|
+
if (!entry || !parts) return;
|
|
6309
|
+
const refused = parts.restrictions.some((r) => r.part === change.part);
|
|
6310
|
+
if (refused) return;
|
|
6311
|
+
switch (change.part) {
|
|
6312
|
+
case "transcript":
|
|
6313
|
+
entry.parts = {
|
|
6314
|
+
...parts,
|
|
6315
|
+
transcript: upsert2(
|
|
6316
|
+
parts.transcript,
|
|
6317
|
+
change.row,
|
|
6318
|
+
change.removedId,
|
|
6319
|
+
(a, b) => ascending(a.startedAt, b.startedAt) || byId(a, b)
|
|
6320
|
+
)
|
|
6321
|
+
};
|
|
6322
|
+
break;
|
|
6323
|
+
case "notes":
|
|
6324
|
+
entry.parts = {
|
|
6325
|
+
...parts,
|
|
6326
|
+
notes: upsert2(
|
|
6327
|
+
parts.notes,
|
|
6328
|
+
change.row,
|
|
6329
|
+
change.removedId,
|
|
6330
|
+
(a, b) => ascending(a.createdAt, b.createdAt) || byId(a, b)
|
|
6331
|
+
)
|
|
6332
|
+
};
|
|
6333
|
+
break;
|
|
6334
|
+
case "attendance":
|
|
6335
|
+
entry.parts = {
|
|
6336
|
+
...parts,
|
|
6337
|
+
attendees: upsert2(
|
|
6338
|
+
parts.attendees,
|
|
6339
|
+
change.row,
|
|
6340
|
+
change.removedId,
|
|
6341
|
+
(a, b) => ascending(a.joinedAt, b.joinedAt) || byId(a, b)
|
|
6342
|
+
)
|
|
6343
|
+
};
|
|
6344
|
+
break;
|
|
6345
|
+
case "recording":
|
|
6346
|
+
entry.parts = {
|
|
6347
|
+
...parts,
|
|
6348
|
+
// Newest first, as the read orders them.
|
|
6349
|
+
recordings: upsert2(
|
|
6350
|
+
parts.recordings,
|
|
6351
|
+
change.row,
|
|
6352
|
+
change.removedId,
|
|
6353
|
+
(a, b) => ascending(b.startedAt, a.startedAt) || byId(a, b)
|
|
6354
|
+
)
|
|
6355
|
+
};
|
|
6356
|
+
break;
|
|
6357
|
+
}
|
|
6358
|
+
assemble(entry);
|
|
6359
|
+
},
|
|
6360
|
+
hold(key, open, owner = null) {
|
|
6361
|
+
const entry = entryOf(key);
|
|
6362
|
+
if (entry.grace !== null) {
|
|
6363
|
+
clearTimeout(entry.grace);
|
|
6364
|
+
entry.grace = null;
|
|
6365
|
+
}
|
|
6366
|
+
if (entry.close !== null && entry.owner !== owner) {
|
|
6367
|
+
entry.close();
|
|
6368
|
+
entry.close = null;
|
|
6369
|
+
}
|
|
6370
|
+
if (entry.close === null) {
|
|
6371
|
+
entry.close = open();
|
|
6372
|
+
entry.owner = owner;
|
|
6373
|
+
}
|
|
6374
|
+
entry.holders += 1;
|
|
6375
|
+
let released = false;
|
|
6376
|
+
return () => {
|
|
6377
|
+
if (released) return;
|
|
6378
|
+
released = true;
|
|
6379
|
+
entry.holders -= 1;
|
|
6380
|
+
if (entry.holders > 0) return;
|
|
6381
|
+
entry.grace = setTimeout(() => {
|
|
6382
|
+
entry.grace = null;
|
|
6383
|
+
if (entry.holders > 0) return;
|
|
6384
|
+
entry.close?.();
|
|
6385
|
+
entry.close = null;
|
|
6386
|
+
entry.fresh = false;
|
|
6387
|
+
}, graceMs);
|
|
6388
|
+
};
|
|
6389
|
+
},
|
|
6390
|
+
reset() {
|
|
6391
|
+
for (const entry of entries.values()) {
|
|
6392
|
+
if (entry.grace !== null) clearTimeout(entry.grace);
|
|
6393
|
+
entry.close?.();
|
|
6394
|
+
}
|
|
6395
|
+
entries.clear();
|
|
6396
|
+
notify();
|
|
6397
|
+
}
|
|
6398
|
+
};
|
|
6399
|
+
}
|
|
6400
|
+
|
|
6401
|
+
// src/core/layout.ts
|
|
6402
|
+
var DEFAULT_PAGE_SIZE = 12;
|
|
6403
|
+
function orderParticipants(participants, activeSpeakers) {
|
|
6404
|
+
const speakerRank = /* @__PURE__ */ new Map();
|
|
6405
|
+
activeSpeakers.forEach((identity, index) => speakerRank.set(identity, index));
|
|
6406
|
+
return [...participants].sort((a, b) => {
|
|
6407
|
+
const speakerA = speakerRank.get(a.identity) ?? Number.MAX_SAFE_INTEGER;
|
|
6408
|
+
const speakerB = speakerRank.get(b.identity) ?? Number.MAX_SAFE_INTEGER;
|
|
6409
|
+
if (speakerA !== speakerB) return speakerA - speakerB;
|
|
6410
|
+
if (a.handRaised !== b.handRaised) return a.handRaised ? -1 : 1;
|
|
6411
|
+
if (a.cameraEnabled !== b.cameraEnabled) return a.cameraEnabled ? -1 : 1;
|
|
6412
|
+
if (a.joinedAt !== b.joinedAt) return a.joinedAt < b.joinedAt ? -1 : 1;
|
|
6413
|
+
return a.identity < b.identity ? -1 : 1;
|
|
6414
|
+
});
|
|
6415
|
+
}
|
|
6416
|
+
function computeStage(args) {
|
|
6417
|
+
const pageSize = Math.max(1, args.pageSize ?? DEFAULT_PAGE_SIZE);
|
|
6418
|
+
const ordered = orderParticipants(args.participants, args.activeSpeakers);
|
|
6419
|
+
const sharer = ordered.find((participant) => participant.screenSharing) ?? null;
|
|
6420
|
+
const pinnedParticipant = args.pinned === null ? null : ordered.find((participant) => participant.identity === args.pinned) ?? null;
|
|
6421
|
+
const spotlit = args.spotlight == null ? null : ordered.find((participant) => participant.identity === args.spotlight) ?? null;
|
|
6422
|
+
const feature = sharer !== null ? sharer : pinnedParticipant !== null && args.layout !== "grid" ? pinnedParticipant : spotlit !== null ? spotlit : args.layout === "grid" ? null : ordered[0] ?? null;
|
|
6423
|
+
const rest = feature === null ? ordered : ordered.filter((participant) => participant.identity !== feature.identity);
|
|
6424
|
+
const pageCount = Math.max(1, Math.ceil(rest.length / pageSize));
|
|
6425
|
+
const page = Math.min(Math.max(0, args.page ?? 0), pageCount - 1);
|
|
6426
|
+
const tiles = rest.slice(page * pageSize, page * pageSize + pageSize);
|
|
6427
|
+
return {
|
|
6428
|
+
feature,
|
|
6429
|
+
tiles,
|
|
6430
|
+
overflow: rest.length - tiles.length,
|
|
6431
|
+
page,
|
|
6432
|
+
pageCount,
|
|
6433
|
+
presenting: sharer !== null
|
|
6434
|
+
};
|
|
6435
|
+
}
|
|
6436
|
+
function gridColumns(count2) {
|
|
6437
|
+
if (count2 <= 1) return 1;
|
|
6438
|
+
if (count2 <= 4) return 2;
|
|
6439
|
+
if (count2 <= 9) return 3;
|
|
6440
|
+
if (count2 <= 16) return 4;
|
|
6441
|
+
return 5;
|
|
6442
|
+
}
|
|
6443
|
+
|
|
6227
6444
|
// src/react/hooks.ts
|
|
6228
6445
|
var EMPTY_NAMES = {};
|
|
6229
6446
|
var NO_RUNTIME_REMEDY = "Render this inside a <MeetProvider> that has a Supabase client, an organization id and an identity (userId or guestName). The provider stays inert until all three are real, and while it is inert this package's components render nothing rather than a dead control.";
|
|
@@ -6809,16 +7026,22 @@ function useMeeting() {
|
|
|
6809
7026
|
function useMeetingId() {
|
|
6810
7027
|
return useMeetSnapshot()?.meeting?.id ?? null;
|
|
6811
7028
|
}
|
|
7029
|
+
var RECORD_CACHE_KEY = /* @__PURE__ */ Symbol.for("@ai-matrx/meet/meeting-record-cache");
|
|
7030
|
+
function meetingRecordCache() {
|
|
7031
|
+
const holder = globalThis;
|
|
7032
|
+
let cache = holder[RECORD_CACHE_KEY];
|
|
7033
|
+
if (cache === void 0) {
|
|
7034
|
+
cache = createMeetingRecordCache();
|
|
7035
|
+
holder[RECORD_CACHE_KEY] = cache;
|
|
7036
|
+
}
|
|
7037
|
+
return cache;
|
|
7038
|
+
}
|
|
7039
|
+
var rowIdOf = (row) => typeof row["id"] === "string" ? row["id"] : void 0;
|
|
6812
7040
|
function useMeetingRecord(meeting) {
|
|
6813
7041
|
const host = useMeetHost();
|
|
6814
7042
|
const repository = host?.repository ?? null;
|
|
6815
7043
|
const ai = host?.ai ?? null;
|
|
6816
7044
|
const readerId = host?.identity.userId ?? null;
|
|
6817
|
-
const [recordReaderId, setRecordReaderId] = (0, import_react3.useState)(readerId);
|
|
6818
|
-
const [record, setRecord] = (0, import_react3.useState)(null);
|
|
6819
|
-
const [loading, setLoading] = (0, import_react3.useState)(true);
|
|
6820
|
-
const [failure, setFailure] = (0, import_react3.useState)(null);
|
|
6821
|
-
const [nonce, setNonce] = (0, import_react3.useState)(0);
|
|
6822
7045
|
const [asking, setAsking] = (0, import_react3.useState)(false);
|
|
6823
7046
|
const [answer, setAnswer] = (0, import_react3.useState)(null);
|
|
6824
7047
|
const [coverage, setCoverage] = (0, import_react3.useState)(null);
|
|
@@ -6827,57 +7050,107 @@ function useMeetingRecord(meeting) {
|
|
|
6827
7050
|
const api = host?.api ?? null;
|
|
6828
7051
|
const tokens = host?.tokens ?? null;
|
|
6829
7052
|
const roomName = meeting?.roomName ?? null;
|
|
6830
|
-
(0,
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
// answers members and invitees; a person from another organization
|
|
6846
|
-
// the host admitted — or a guest who later made an account — reads
|
|
6847
|
-
// the guest share through the server, with their session as the pass.
|
|
6848
|
-
api !== null && direct.restrictions.some((part) => part.part === "notes") ? loadGuestMeetingRecord({
|
|
7053
|
+
const manager = (0, import_react4.useRealtimeManager)();
|
|
7054
|
+
const cache = meetingRecordCache();
|
|
7055
|
+
const key = repository !== null && meetingId !== null ? `${readerId ?? `guest:${roomName ?? "-"}`}|${meetingId}` : null;
|
|
7056
|
+
const state = (0, import_react3.useSyncExternalStore)(
|
|
7057
|
+
cache.subscribe,
|
|
7058
|
+
() => cache.state(key),
|
|
7059
|
+
() => cache.state(null)
|
|
7060
|
+
);
|
|
7061
|
+
const readRef = (0, import_react3.useRef)(() => Promise.reject(new Error("not ready")));
|
|
7062
|
+
readRef.current = async () => {
|
|
7063
|
+
if (repository === null || meeting === null || meetingId === null) throw new Error("No meeting to read.");
|
|
7064
|
+
if (readerId === null && api !== null && tokens !== null && roomName !== null) {
|
|
7065
|
+
return {
|
|
7066
|
+
kind: "bundle",
|
|
7067
|
+
bundle: await loadGuestMeetingRecord({
|
|
6849
7068
|
api,
|
|
6850
7069
|
repository,
|
|
6851
7070
|
meetingId,
|
|
6852
7071
|
meeting,
|
|
6853
|
-
roomToken:
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
if (!live) return;
|
|
6867
|
-
setFailure({
|
|
6868
|
-
message: thrown.message,
|
|
6869
|
-
remedy: thrown.remedy ?? "The meeting record could not be read. Reload the page; nothing was changed."
|
|
7072
|
+
roomToken: tokens.remembered(roomName)
|
|
7073
|
+
})
|
|
7074
|
+
};
|
|
7075
|
+
}
|
|
7076
|
+
const parts = await loadMeetingRecordParts(repository, meetingId, { userId: readerId });
|
|
7077
|
+
if (api !== null && parts.restrictions.some((part) => part.part === "notes")) {
|
|
7078
|
+
const viaServer = await loadGuestMeetingRecord({
|
|
7079
|
+
api,
|
|
7080
|
+
repository,
|
|
7081
|
+
meetingId,
|
|
7082
|
+
meeting,
|
|
7083
|
+
roomToken: null,
|
|
7084
|
+
session: true
|
|
6870
7085
|
});
|
|
6871
|
-
|
|
7086
|
+
if (viaServer.restrictions.length < parts.restrictions.length) return { kind: "bundle", bundle: viaServer };
|
|
7087
|
+
}
|
|
7088
|
+
return { kind: "parts", meeting, parts };
|
|
7089
|
+
};
|
|
7090
|
+
(0, import_react3.useEffect)(() => {
|
|
7091
|
+
if (key === null) return;
|
|
7092
|
+
void cache.ensure(key, () => readRef.current());
|
|
7093
|
+
}, [cache, key]);
|
|
7094
|
+
(0, import_react3.useEffect)(() => {
|
|
7095
|
+
if (key !== null && meeting !== null) cache.setMeeting(key, meeting);
|
|
7096
|
+
}, [cache, key, meeting]);
|
|
7097
|
+
(0, import_react3.useEffect)(() => {
|
|
7098
|
+
if (key === null || manager === null || repository === null || meetingId === null || readerId === null) {
|
|
7099
|
+
return void 0;
|
|
7100
|
+
}
|
|
7101
|
+
const repo = repository;
|
|
7102
|
+
const binding = (table, apply) => ({
|
|
7103
|
+
event: "*",
|
|
7104
|
+
schema: repo.schema,
|
|
7105
|
+
table,
|
|
7106
|
+
filter: `meeting_id=eq.${meetingId}`,
|
|
7107
|
+
rowId: rowIdOf,
|
|
7108
|
+
onChange: ({ row, payload }) => {
|
|
7109
|
+
if (row === null) return;
|
|
7110
|
+
const gone = payload.eventType === "DELETE";
|
|
7111
|
+
apply(gone ? null : row, gone ? rowIdOf(row) : void 0);
|
|
7112
|
+
}
|
|
6872
7113
|
});
|
|
6873
|
-
return (
|
|
6874
|
-
|
|
6875
|
-
|
|
6876
|
-
|
|
7114
|
+
return cache.hold(
|
|
7115
|
+
key,
|
|
7116
|
+
() => {
|
|
7117
|
+
const handle = manager.open({
|
|
7118
|
+
topic: meetingTopic(meetingId),
|
|
7119
|
+
postgresChanges: [
|
|
7120
|
+
binding(
|
|
7121
|
+
repo.tables.notes,
|
|
7122
|
+
(row, removedId) => cache.apply(key, { part: "notes", row: row && repo.projectNote(row), removedId })
|
|
7123
|
+
),
|
|
7124
|
+
binding(
|
|
7125
|
+
repo.tables.transcripts,
|
|
7126
|
+
(row, removedId) => cache.apply(key, { part: "transcript", row: row && repo.projectSegment(row), removedId })
|
|
7127
|
+
),
|
|
7128
|
+
binding(
|
|
7129
|
+
repo.tables.participants,
|
|
7130
|
+
(row, removedId) => cache.apply(key, { part: "attendance", row: row && repo.projectAttendee(row), removedId })
|
|
7131
|
+
),
|
|
7132
|
+
binding(
|
|
7133
|
+
repo.tables.recordings,
|
|
7134
|
+
(row, removedId) => (
|
|
7135
|
+
// An archived recording is off the record (the read filters it the same way).
|
|
7136
|
+
row !== null && row["deleted_at"] != null ? cache.apply(key, { part: "recording", row: null, removedId: rowIdOf(row) }) : cache.apply(key, { part: "recording", row: row && repo.projectRecording(row), removedId })
|
|
7137
|
+
)
|
|
7138
|
+
)
|
|
7139
|
+
],
|
|
7140
|
+
// Realtime has no replay: a socket that blipped reads the record again.
|
|
7141
|
+
onBackfill: async () => {
|
|
7142
|
+
await cache.ensure(key, () => readRef.current(), { force: true });
|
|
7143
|
+
}
|
|
7144
|
+
});
|
|
7145
|
+
return () => handle.close();
|
|
7146
|
+
},
|
|
7147
|
+
manager
|
|
7148
|
+
);
|
|
7149
|
+
}, [cache, key, manager, repository, meetingId, readerId]);
|
|
6877
7150
|
return {
|
|
6878
|
-
loading: loading && failure === null,
|
|
6879
|
-
record:
|
|
6880
|
-
failure,
|
|
7151
|
+
loading: state.loading && state.failure === null,
|
|
7152
|
+
record: state.record,
|
|
7153
|
+
failure: state.failure,
|
|
6881
7154
|
asking,
|
|
6882
7155
|
answer,
|
|
6883
7156
|
coverage,
|
|
@@ -6908,7 +7181,9 @@ function useMeetingRecord(meeting) {
|
|
|
6908
7181
|
},
|
|
6909
7182
|
[ai, meetingId]
|
|
6910
7183
|
),
|
|
6911
|
-
reload: (0, import_react3.useCallback)(() =>
|
|
7184
|
+
reload: (0, import_react3.useCallback)(() => {
|
|
7185
|
+
if (key !== null) void cache.ensure(key, () => readRef.current(), { force: true });
|
|
7186
|
+
}, [cache, key])
|
|
6912
7187
|
};
|
|
6913
7188
|
}
|
|
6914
7189
|
function useMeetings(limit = 25, organizationFilter = null) {
|
|
@@ -6995,7 +7270,7 @@ function useGuestRecordAccess(meeting) {
|
|
|
6995
7270
|
}
|
|
6996
7271
|
|
|
6997
7272
|
// src/react/components.tsx
|
|
6998
|
-
var
|
|
7273
|
+
var import_react6 = require("react");
|
|
6999
7274
|
var import_design_system = require("@ai-matrx/design-system");
|
|
7000
7275
|
var import_format4 = require("@ai-matrx/kit/format");
|
|
7001
7276
|
|
|
@@ -7440,7 +7715,7 @@ function countLabel(count2, singular, plural = `${singular}s`) {
|
|
|
7440
7715
|
}
|
|
7441
7716
|
|
|
7442
7717
|
// src/react/collab.tsx
|
|
7443
|
-
var
|
|
7718
|
+
var import_react5 = require("react");
|
|
7444
7719
|
var import_format3 = require("@ai-matrx/kit/format");
|
|
7445
7720
|
|
|
7446
7721
|
// src/react/icons.tsx
|
|
@@ -7717,8 +7992,8 @@ function useCollab() {
|
|
|
7717
7992
|
};
|
|
7718
7993
|
}
|
|
7719
7994
|
function useNotice() {
|
|
7720
|
-
const [notice, setNotice] = (0,
|
|
7721
|
-
(0,
|
|
7995
|
+
const [notice, setNotice] = (0, import_react5.useState)(null);
|
|
7996
|
+
(0, import_react5.useEffect)(() => {
|
|
7722
7997
|
if (notice === null) return void 0;
|
|
7723
7998
|
const timer = setTimeout(() => setNotice(null), notice.failed ? 7e3 : 3e3);
|
|
7724
7999
|
return () => clearTimeout(timer);
|
|
@@ -7764,7 +8039,7 @@ function ActivitiesControl({
|
|
|
7764
8039
|
active,
|
|
7765
8040
|
onOpen
|
|
7766
8041
|
}) {
|
|
7767
|
-
const [open, setOpen] = (0,
|
|
8042
|
+
const [open, setOpen] = (0, import_react5.useState)(false);
|
|
7768
8043
|
const available = useAvailableActivities();
|
|
7769
8044
|
const attention = useActivityAttention();
|
|
7770
8045
|
if (available.length === 0) return null;
|
|
@@ -7792,11 +8067,11 @@ function ActivitiesControl({
|
|
|
7792
8067
|
}
|
|
7793
8068
|
function PollComposer({ maxOptions, onDone }) {
|
|
7794
8069
|
const { act } = useCollab();
|
|
7795
|
-
const [question, setQuestion] = (0,
|
|
7796
|
-
const [options, setOptions] = (0,
|
|
7797
|
-
const [multiple, setMultiple] = (0,
|
|
7798
|
-
const [anonymous, setAnonymous] = (0,
|
|
7799
|
-
const [busy, setBusy] = (0,
|
|
8070
|
+
const [question, setQuestion] = (0, import_react5.useState)("");
|
|
8071
|
+
const [options, setOptions] = (0, import_react5.useState)(["", ""]);
|
|
8072
|
+
const [multiple, setMultiple] = (0, import_react5.useState)(false);
|
|
8073
|
+
const [anonymous, setAnonymous] = (0, import_react5.useState)(false);
|
|
8074
|
+
const [busy, setBusy] = (0, import_react5.useState)(false);
|
|
7800
8075
|
const [notice, show] = useNotice();
|
|
7801
8076
|
const filled = options.map((o) => o.trim()).filter(Boolean);
|
|
7802
8077
|
const ready = question.trim().length > 0 && filled.length >= 2;
|
|
@@ -7877,9 +8152,9 @@ function PollComposer({ maxOptions, onDone }) {
|
|
|
7877
8152
|
}
|
|
7878
8153
|
function PollCard({ poll }) {
|
|
7879
8154
|
const { act, isHost } = useCollab();
|
|
7880
|
-
const [picked, setPicked] = (0,
|
|
8155
|
+
const [picked, setPicked] = (0, import_react5.useState)(poll.myVote.slice());
|
|
7881
8156
|
const [notice, show] = useNotice();
|
|
7882
|
-
(0,
|
|
8157
|
+
(0, import_react5.useEffect)(() => setPicked(poll.myVote.slice()), [poll.myVote]);
|
|
7883
8158
|
const counts = poll.options.some((o) => o.votes !== void 0);
|
|
7884
8159
|
const total = poll.options.reduce((sum, o) => sum + (o.votes ?? 0), 0);
|
|
7885
8160
|
const canVote = poll.state === "live";
|
|
@@ -7948,7 +8223,7 @@ function PollCard({ poll }) {
|
|
|
7948
8223
|
}
|
|
7949
8224
|
function PollsPanel({ onClose }) {
|
|
7950
8225
|
const { collab, isHost } = useCollab();
|
|
7951
|
-
const [composing, setComposing] = (0,
|
|
8226
|
+
const [composing, setComposing] = (0, import_react5.useState)(false);
|
|
7952
8227
|
const polls = collab?.polls ?? [];
|
|
7953
8228
|
const maxOptions = collab?.settings?.pollMaxOptions ?? 10;
|
|
7954
8229
|
const ordered = [...polls].reverse();
|
|
@@ -7962,8 +8237,8 @@ function PollsPanel({ onClose }) {
|
|
|
7962
8237
|
}
|
|
7963
8238
|
function QuestionCard({ question }) {
|
|
7964
8239
|
const { act, isHost } = useCollab();
|
|
7965
|
-
const [answering, setAnswering] = (0,
|
|
7966
|
-
const [reply, setReply] = (0,
|
|
8240
|
+
const [answering, setAnswering] = (0, import_react5.useState)(false);
|
|
8241
|
+
const [reply, setReply] = (0, import_react5.useState)("");
|
|
7967
8242
|
const [notice, show] = useNotice();
|
|
7968
8243
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { className: `mx-meet__collab-card mx-meet__question mx-meet__question--${question.state}`, children: [
|
|
7969
8244
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mx-meet__question-row", children: [
|
|
@@ -8041,9 +8316,9 @@ function QuestionCard({ question }) {
|
|
|
8041
8316
|
}
|
|
8042
8317
|
function QaPanel({ onClose }) {
|
|
8043
8318
|
const { collab, act } = useCollab();
|
|
8044
|
-
const [draft, setDraft] = (0,
|
|
8045
|
-
const [anonymous, setAnonymous] = (0,
|
|
8046
|
-
const [order, setOrder] = (0,
|
|
8319
|
+
const [draft, setDraft] = (0, import_react5.useState)("");
|
|
8320
|
+
const [anonymous, setAnonymous] = (0, import_react5.useState)(false);
|
|
8321
|
+
const [order, setOrder] = (0, import_react5.useState)("popular");
|
|
8047
8322
|
const [notice, show] = useNotice();
|
|
8048
8323
|
const allowAnonymous = collab?.settings?.qaAnonymousAllowed === true;
|
|
8049
8324
|
const questions = [...collab?.questions ?? []];
|
|
@@ -8132,12 +8407,12 @@ function StrokeView({ stroke, onPick }) {
|
|
|
8132
8407
|
}
|
|
8133
8408
|
function WhiteboardPanel({ onClose }) {
|
|
8134
8409
|
const { collab, act, isHost, localIdentity } = useCollab();
|
|
8135
|
-
const [tool, setTool] = (0,
|
|
8136
|
-
const [color, setColor] = (0,
|
|
8137
|
-
const [drawing, setDrawing] = (0,
|
|
8138
|
-
const [pending, setPending] = (0,
|
|
8410
|
+
const [tool, setTool] = (0, import_react5.useState)("pen");
|
|
8411
|
+
const [color, setColor] = (0, import_react5.useState)(INK[0]);
|
|
8412
|
+
const [drawing, setDrawing] = (0, import_react5.useState)(null);
|
|
8413
|
+
const [pending, setPending] = (0, import_react5.useState)([]);
|
|
8139
8414
|
const [notice, show] = useNotice();
|
|
8140
|
-
const svgRef = (0,
|
|
8415
|
+
const svgRef = (0, import_react5.useRef)(null);
|
|
8141
8416
|
const strokes = collab?.strokes ?? [];
|
|
8142
8417
|
const mine = strokes.filter((s) => s.by === localIdentity);
|
|
8143
8418
|
const point = (event) => {
|
|
@@ -8278,8 +8553,8 @@ function clock(ms2) {
|
|
|
8278
8553
|
}
|
|
8279
8554
|
var BREAKOUT_EXPIRE_RETRY_MS = 5e3;
|
|
8280
8555
|
function useNow(active) {
|
|
8281
|
-
const [now, setNow] = (0,
|
|
8282
|
-
(0,
|
|
8556
|
+
const [now, setNow] = (0, import_react5.useState)(() => Date.now());
|
|
8557
|
+
(0, import_react5.useEffect)(() => {
|
|
8283
8558
|
if (!active) return void 0;
|
|
8284
8559
|
const timer = setInterval(() => setNow(Date.now()), 1e3);
|
|
8285
8560
|
return () => clearInterval(timer);
|
|
@@ -8293,11 +8568,11 @@ function BreakoutSetup() {
|
|
|
8293
8568
|
const people = (snapshot?.participants ?? []).filter(
|
|
8294
8569
|
(p) => !p.isAgent && p.role !== "host" && p.role !== "cohost"
|
|
8295
8570
|
);
|
|
8296
|
-
const [count2, setCount] = (0,
|
|
8297
|
-
const [mode, setMode] = (0,
|
|
8298
|
-
const [minutes, setMinutes] = (0,
|
|
8299
|
-
const [manual, setManual] = (0,
|
|
8300
|
-
const [busy, setBusy] = (0,
|
|
8571
|
+
const [count2, setCount] = (0, import_react5.useState)(Math.min(Math.max(2, Math.ceil(people.length / 4)), settings?.breakoutMaxRooms ?? 20));
|
|
8572
|
+
const [mode, setMode] = (0, import_react5.useState)("auto");
|
|
8573
|
+
const [minutes, setMinutes] = (0, import_react5.useState)(settings?.breakoutDefaultMinutes ?? 15);
|
|
8574
|
+
const [manual, setManual] = (0, import_react5.useState)({});
|
|
8575
|
+
const [busy, setBusy] = (0, import_react5.useState)(false);
|
|
8301
8576
|
const [notice, show] = useNotice();
|
|
8302
8577
|
const max = settings?.breakoutMaxRooms ?? 20;
|
|
8303
8578
|
const rooms = Math.min(Math.max(1, count2), max);
|
|
@@ -8413,7 +8688,7 @@ function BreakoutRun({ plan }) {
|
|
|
8413
8688
|
const snapshot = useMeetSnapshot();
|
|
8414
8689
|
const now = useNow(plan.endsAt !== null);
|
|
8415
8690
|
const remaining = breakoutRemainingMs(plan, now);
|
|
8416
|
-
const [broadcast, setBroadcast] = (0,
|
|
8691
|
+
const [broadcast, setBroadcast] = (0, import_react5.useState)("");
|
|
8417
8692
|
const [notice, show] = useNotice();
|
|
8418
8693
|
const nameOf = (identity) => displayNameFor(snapshot?.names ?? {}, identity, snapshot?.participants.find((p) => p.identity === identity)?.displayName);
|
|
8419
8694
|
const mine = assignedRoom(plan, localIdentity);
|
|
@@ -8523,11 +8798,11 @@ function BreakoutBanner() {
|
|
|
8523
8798
|
const now = useNow(open?.endsAt != null);
|
|
8524
8799
|
const remaining = breakoutRemainingMs(open, now);
|
|
8525
8800
|
const assigned = assignedRoom(open, localIdentity);
|
|
8526
|
-
const [dismissedBroadcast, setDismissedBroadcast] = (0,
|
|
8527
|
-
const [failure, setFailure] = (0,
|
|
8528
|
-
const expireAsked = (0,
|
|
8801
|
+
const [dismissedBroadcast, setDismissedBroadcast] = (0, import_react5.useState)(null);
|
|
8802
|
+
const [failure, setFailure] = (0, import_react5.useState)(null);
|
|
8803
|
+
const expireAsked = (0, import_react5.useRef)(null);
|
|
8529
8804
|
const moveAt = collab?.moveRequest?.at ?? null;
|
|
8530
|
-
(0,
|
|
8805
|
+
(0, import_react5.useEffect)(() => {
|
|
8531
8806
|
const request = host?.store.snapshot().collab.moveRequest ?? null;
|
|
8532
8807
|
if (request === null || host === null) return;
|
|
8533
8808
|
host.store.patch({ collab: { ...host.store.snapshot().collab, moveRequest: null } });
|
|
@@ -8535,7 +8810,7 @@ function BreakoutBanner() {
|
|
|
8535
8810
|
if ((here ?? null) === request.roomId) return;
|
|
8536
8811
|
void moveTo(request.roomId).then((result) => setFailure(result.ok ? null : result.message));
|
|
8537
8812
|
}, [moveAt, host, moveTo]);
|
|
8538
|
-
(0,
|
|
8813
|
+
(0, import_react5.useEffect)(() => {
|
|
8539
8814
|
if (open === null || remaining === null || remaining > 0) return;
|
|
8540
8815
|
const asked = expireAsked.current;
|
|
8541
8816
|
if (asked !== null && asked.id === open.id && now - asked.at < BREAKOUT_EXPIRE_RETRY_MS) return;
|
|
@@ -8585,13 +8860,13 @@ function useCaptionTranslation(lines) {
|
|
|
8585
8860
|
const snapshot = useMeetSnapshot();
|
|
8586
8861
|
const collab = snapshot?.collab ?? null;
|
|
8587
8862
|
const language = collab?.captionLanguage ?? null;
|
|
8588
|
-
const asked = (0,
|
|
8863
|
+
const asked = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
|
|
8589
8864
|
const translations = collab?.captionTranslations ?? {};
|
|
8590
8865
|
const missing = lines.filter((line) => line.final && translations[line.id] === void 0).map(({ id, text: text3 }) => ({ id, text: text3 }));
|
|
8591
8866
|
const key = `${language ?? ""}|${missing.map((l) => l.id).join(",")}`;
|
|
8592
|
-
const pending = (0,
|
|
8867
|
+
const pending = (0, import_react5.useRef)(missing);
|
|
8593
8868
|
pending.current = missing;
|
|
8594
|
-
(0,
|
|
8869
|
+
(0, import_react5.useEffect)(() => {
|
|
8595
8870
|
if (host === null || language === null) return;
|
|
8596
8871
|
const batch = pending.current.filter((line) => !asked.current.has(`${language}:${line.id}`)).slice(-20);
|
|
8597
8872
|
if (batch.length === 0) return;
|
|
@@ -8646,9 +8921,9 @@ function CaptionLanguageSettings() {
|
|
|
8646
8921
|
function useCollabPanelRequest(onRequest) {
|
|
8647
8922
|
const host = useMeetHost();
|
|
8648
8923
|
const at = useMeetSnapshot()?.collab.panelRequest?.at ?? null;
|
|
8649
|
-
const callback = (0,
|
|
8924
|
+
const callback = (0, import_react5.useRef)(onRequest);
|
|
8650
8925
|
callback.current = onRequest;
|
|
8651
|
-
(0,
|
|
8926
|
+
(0, import_react5.useEffect)(() => {
|
|
8652
8927
|
const request = host?.store.snapshot().collab.panelRequest ?? null;
|
|
8653
8928
|
if (request === null || host === null) return;
|
|
8654
8929
|
host.store.patch({ collab: { ...host.store.snapshot().collab, panelRequest: null } });
|
|
@@ -8757,7 +9032,7 @@ function ParticipantTile({
|
|
|
8757
9032
|
const host = useMeetHost();
|
|
8758
9033
|
const snapshot = useMeetSnapshot();
|
|
8759
9034
|
const queue = useHandQueue();
|
|
8760
|
-
const [menu, setMenu] = (0,
|
|
9035
|
+
const [menu, setMenu] = (0, import_react6.useState)(false);
|
|
8761
9036
|
const videoRef = useTrack(
|
|
8762
9037
|
participant.identity,
|
|
8763
9038
|
participant.screenSharing ? "screen" : "camera"
|
|
@@ -8871,17 +9146,17 @@ var MEET_REACTIONS = ["\u{1F496}", "\u{1F44D}", "\u{1F389}", "\u{1F44F}", "\u{1F
|
|
|
8871
9146
|
function ControlBar({ onLeave }) {
|
|
8872
9147
|
const room = useRoom();
|
|
8873
9148
|
const recording = useRecording();
|
|
8874
|
-
const [panel, setPanel] = (0,
|
|
8875
|
-
const [chatTo, setChatTo] = (0,
|
|
8876
|
-
const [popover, setPopover] = (0,
|
|
8877
|
-
const [shortcuts, setShortcuts] = (0,
|
|
9149
|
+
const [panel, setPanel] = (0, import_react6.useState)("none");
|
|
9150
|
+
const [chatTo, setChatTo] = (0, import_react6.useState)(null);
|
|
9151
|
+
const [popover, setPopover] = (0, import_react6.useState)("none");
|
|
9152
|
+
const [shortcuts, setShortcuts] = (0, import_react6.useState)(false);
|
|
8878
9153
|
const snapshot = useMeetSnapshot();
|
|
8879
9154
|
const lobby = useLobby();
|
|
8880
9155
|
const controls = useHostControls();
|
|
8881
9156
|
const queue = useHandQueue();
|
|
8882
9157
|
const micUnavailable = useLocalMedia().microphone.unavailable;
|
|
8883
9158
|
const unread = useUnreadChat(panel === "chat");
|
|
8884
|
-
const [whiteboard, setWhiteboard] = (0,
|
|
9159
|
+
const [whiteboard, setWhiteboard] = (0, import_react6.useState)(false);
|
|
8885
9160
|
const toggle = (next) => setPanel(panel === next ? "none" : next);
|
|
8886
9161
|
const openActivity = (activity) => {
|
|
8887
9162
|
if (activity === "whiteboard") setWhiteboard(true);
|
|
@@ -8892,7 +9167,7 @@ function ControlBar({ onLeave }) {
|
|
|
8892
9167
|
});
|
|
8893
9168
|
const privateChatAt = snapshot?.privateChatRequest?.at ?? null;
|
|
8894
9169
|
const meetStore = useMeetHost()?.store ?? null;
|
|
8895
|
-
(0,
|
|
9170
|
+
(0, import_react6.useEffect)(() => {
|
|
8896
9171
|
const request = meetStore?.snapshot().privateChatRequest ?? null;
|
|
8897
9172
|
if (request === null) return;
|
|
8898
9173
|
setChatTo(request.to);
|
|
@@ -9130,13 +9405,13 @@ function useUnreadChat(open) {
|
|
|
9130
9405
|
const snapshot = useMeetSnapshot();
|
|
9131
9406
|
const chat = snapshot?.chat ?? [];
|
|
9132
9407
|
const local = snapshot?.localIdentity ?? null;
|
|
9133
|
-
const [seen, setSeen] = (0,
|
|
9134
|
-
(0,
|
|
9408
|
+
const [seen, setSeen] = (0, import_react6.useState)(0);
|
|
9409
|
+
(0, import_react6.useEffect)(() => {
|
|
9135
9410
|
if (open) setSeen(chat.length);
|
|
9136
9411
|
}, [open, chat.length]);
|
|
9137
9412
|
const loaded = snapshot?.chatLoaded === true;
|
|
9138
|
-
const [baseline, setBaseline] = (0,
|
|
9139
|
-
(0,
|
|
9413
|
+
const [baseline, setBaseline] = (0, import_react6.useState)(null);
|
|
9414
|
+
(0, import_react6.useEffect)(() => {
|
|
9140
9415
|
if (loaded && baseline === null) setBaseline(chat.length);
|
|
9141
9416
|
}, [loaded, baseline, chat.length]);
|
|
9142
9417
|
if (open) return 0;
|
|
@@ -9149,14 +9424,14 @@ function Popover({
|
|
|
9149
9424
|
children,
|
|
9150
9425
|
placement = "up"
|
|
9151
9426
|
}) {
|
|
9152
|
-
const ref = (0,
|
|
9153
|
-
const [style, setStyle] = (0,
|
|
9427
|
+
const ref = (0, import_react6.useRef)(null);
|
|
9428
|
+
const [style, setStyle] = (0, import_react6.useState)({
|
|
9154
9429
|
position: "fixed",
|
|
9155
9430
|
top: 0,
|
|
9156
9431
|
left: 0,
|
|
9157
9432
|
visibility: "hidden"
|
|
9158
9433
|
});
|
|
9159
|
-
(0,
|
|
9434
|
+
(0, import_react6.useLayoutEffect)(() => {
|
|
9160
9435
|
const element = ref.current;
|
|
9161
9436
|
const anchor = element?.parentElement ?? null;
|
|
9162
9437
|
if (element === null || anchor === null) return;
|
|
@@ -9201,7 +9476,7 @@ function Popover({
|
|
|
9201
9476
|
window.removeEventListener("scroll", place, true);
|
|
9202
9477
|
};
|
|
9203
9478
|
}, [placement]);
|
|
9204
|
-
(0,
|
|
9479
|
+
(0, import_react6.useEffect)(() => {
|
|
9205
9480
|
const onKey = (event) => {
|
|
9206
9481
|
if (event.key === "Escape") onClose();
|
|
9207
9482
|
};
|
|
@@ -9235,7 +9510,7 @@ function MenuItem({
|
|
|
9235
9510
|
);
|
|
9236
9511
|
}
|
|
9237
9512
|
function Toast({ text: text3, failed, onDone }) {
|
|
9238
|
-
(0,
|
|
9513
|
+
(0, import_react6.useEffect)(() => {
|
|
9239
9514
|
const timer = setTimeout(onDone, failed ? 7e3 : 4e3);
|
|
9240
9515
|
return () => clearTimeout(timer);
|
|
9241
9516
|
}, [text3, failed, onDone]);
|
|
@@ -9274,7 +9549,7 @@ function MeetingOverlays() {
|
|
|
9274
9549
|
] });
|
|
9275
9550
|
}
|
|
9276
9551
|
function ShortcutsSheet({ onClose }) {
|
|
9277
|
-
(0,
|
|
9552
|
+
(0, import_react6.useEffect)(() => {
|
|
9278
9553
|
const onKey = (event) => {
|
|
9279
9554
|
if (event.key === "Escape") onClose();
|
|
9280
9555
|
};
|
|
@@ -9312,8 +9587,8 @@ function PanelShell({
|
|
|
9312
9587
|
onClose,
|
|
9313
9588
|
children
|
|
9314
9589
|
}) {
|
|
9315
|
-
const ref = (0,
|
|
9316
|
-
(0,
|
|
9590
|
+
const ref = (0, import_react6.useRef)(null);
|
|
9591
|
+
(0, import_react6.useLayoutEffect)(() => {
|
|
9317
9592
|
const panel = ref.current;
|
|
9318
9593
|
const root = panel?.closest(".mx-meet");
|
|
9319
9594
|
const header = root?.querySelector(":scope > .mx-meet__header") ?? null;
|
|
@@ -9340,17 +9615,17 @@ function ChatPanel({
|
|
|
9340
9615
|
}) {
|
|
9341
9616
|
const snapshot = useMeetSnapshot();
|
|
9342
9617
|
const room = useRoom();
|
|
9343
|
-
const [draft, setDraft] = (0,
|
|
9344
|
-
const [recipient, setRecipient] = (0,
|
|
9345
|
-
const listRef = (0,
|
|
9618
|
+
const [draft, setDraft] = (0, import_react6.useState)("");
|
|
9619
|
+
const [recipient, setRecipient] = (0, import_react6.useState)(to);
|
|
9620
|
+
const listRef = (0, import_react6.useRef)(null);
|
|
9346
9621
|
const messages = snapshot?.chat ?? [];
|
|
9347
9622
|
const local = snapshot?.localIdentity ?? null;
|
|
9348
9623
|
const people = (snapshot?.participants ?? []).filter(
|
|
9349
9624
|
(participant) => !participant.isLocal && !participant.isAgent
|
|
9350
9625
|
);
|
|
9351
9626
|
const recipientName = recipient === null ? null : people.find((p) => p.identity === recipient)?.displayName ?? null;
|
|
9352
|
-
(0,
|
|
9353
|
-
(0,
|
|
9627
|
+
(0, import_react6.useEffect)(() => setRecipient(to), [to]);
|
|
9628
|
+
(0, import_react6.useEffect)(() => {
|
|
9354
9629
|
const list = listRef.current;
|
|
9355
9630
|
if (list !== null) list.scrollTop = list.scrollHeight;
|
|
9356
9631
|
}, [messages.length]);
|
|
@@ -9456,8 +9731,8 @@ function PeoplePanel({
|
|
|
9456
9731
|
const snapshot = useMeetSnapshot();
|
|
9457
9732
|
const controls = useHostControls();
|
|
9458
9733
|
const queue = useHandQueue();
|
|
9459
|
-
const [query, setQuery] = (0,
|
|
9460
|
-
const [menuFor, setMenuFor] = (0,
|
|
9734
|
+
const [query, setQuery] = (0, import_react6.useState)("");
|
|
9735
|
+
const [menuFor, setMenuFor] = (0, import_react6.useState)(null);
|
|
9461
9736
|
const myRole = useRole();
|
|
9462
9737
|
const local = snapshot?.localIdentity ?? null;
|
|
9463
9738
|
const everyone = snapshot?.participants ?? [];
|
|
@@ -9582,14 +9857,14 @@ function PersonMenu({
|
|
|
9582
9857
|
const host = useMeetHost();
|
|
9583
9858
|
const snapshot = useMeetSnapshot();
|
|
9584
9859
|
const controls = useHostControls();
|
|
9585
|
-
const [mode, setMode] = (0,
|
|
9586
|
-
const [text3, setText] = (0,
|
|
9860
|
+
const [mode, setMode] = (0, import_react6.useState)("menu");
|
|
9861
|
+
const [text3, setText] = (0, import_react6.useState)("");
|
|
9587
9862
|
const self = participant.identity === snapshot?.localIdentity;
|
|
9588
9863
|
const moderate = controls.canModerate(participant);
|
|
9589
9864
|
const pinned = snapshot?.pinned === participant.identity;
|
|
9590
9865
|
const spotlit = snapshot?.spotlight === participant.identity;
|
|
9591
9866
|
const hasAccount = participant.userId !== null;
|
|
9592
|
-
const [refused, setRefused] = (0,
|
|
9867
|
+
const [refused, setRefused] = (0, import_react6.useState)(false);
|
|
9593
9868
|
const act = (request) => {
|
|
9594
9869
|
setRefused(false);
|
|
9595
9870
|
void controls.run(request).then((result) => {
|
|
@@ -9805,8 +10080,8 @@ function DeviceSettings({
|
|
|
9805
10080
|
const speaker = devices?.selected.audiooutput ?? host.devices.resolve("audiooutput");
|
|
9806
10081
|
const stream = useMicrophoneStream(microphone);
|
|
9807
10082
|
const level = useAudioLevel(stream);
|
|
9808
|
-
const [testing, setTesting] = (0,
|
|
9809
|
-
(0,
|
|
10083
|
+
const [testing, setTesting] = (0, import_react6.useState)(false);
|
|
10084
|
+
(0, import_react6.useEffect)(() => {
|
|
9810
10085
|
void host.devices.refresh();
|
|
9811
10086
|
}, [host]);
|
|
9812
10087
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { className: "mx-meet__section", "aria-label": "Devices", children: [
|
|
@@ -9835,8 +10110,8 @@ function DeviceSettings({
|
|
|
9835
10110
|
}
|
|
9836
10111
|
function EffectsSettings({ preview }) {
|
|
9837
10112
|
const effects = useMediaEffects();
|
|
9838
|
-
const [error, setError] = (0,
|
|
9839
|
-
const fileRef = (0,
|
|
10113
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
10114
|
+
const fileRef = (0, import_react6.useRef)(null);
|
|
9840
10115
|
const supported = effects.backgroundsSupported || preview != null || videoEffectsSupported();
|
|
9841
10116
|
const apply = (next) => {
|
|
9842
10117
|
setError(null);
|
|
@@ -9958,8 +10233,8 @@ async function playTestSound(sinkId) {
|
|
|
9958
10233
|
await context.close();
|
|
9959
10234
|
}
|
|
9960
10235
|
function useMicrophoneStream(deviceId2) {
|
|
9961
|
-
const [stream, setStream] = (0,
|
|
9962
|
-
(0,
|
|
10236
|
+
const [stream, setStream] = (0, import_react6.useState)(null);
|
|
10237
|
+
(0, import_react6.useEffect)(() => {
|
|
9963
10238
|
if (deviceId2 === "off") return void 0;
|
|
9964
10239
|
let live = true;
|
|
9965
10240
|
let opened = null;
|
|
@@ -10060,7 +10335,7 @@ function NoteList({
|
|
|
10060
10335
|
}
|
|
10061
10336
|
function AiPanel({ onClose }) {
|
|
10062
10337
|
const ai = useMeetAi();
|
|
10063
|
-
const [question, setQuestion] = (0,
|
|
10338
|
+
const [question, setQuestion] = (0, import_react6.useState)("");
|
|
10064
10339
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(PanelShell, { title: "Meeting assistant", onClose, children: [
|
|
10065
10340
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NoteTakerRow, {}),
|
|
10066
10341
|
ai.summary !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { className: "mx-meet__note-group", "aria-label": "Summary", children: [
|
|
@@ -10216,16 +10491,16 @@ function PreJoinBody({
|
|
|
10216
10491
|
const recording = useRecording();
|
|
10217
10492
|
const effects = useMediaEffects();
|
|
10218
10493
|
const { notice } = useModerationNotice();
|
|
10219
|
-
const [mode, setMode] = (0,
|
|
10220
|
-
const [microphone, setMicrophone] = (0,
|
|
10221
|
-
const [joining, setJoining] = (0,
|
|
10494
|
+
const [mode, setMode] = (0, import_react6.useState)("video");
|
|
10495
|
+
const [microphone, setMicrophone] = (0, import_react6.useState)(true);
|
|
10496
|
+
const [joining, setJoining] = (0, import_react6.useState)(false);
|
|
10222
10497
|
const camera = devices?.selected.videoinput ?? host.devices.resolve("videoinput");
|
|
10223
10498
|
const mic = devices?.selected.audioinput ?? host.devices.resolve("audioinput");
|
|
10224
10499
|
const preview = useCameraPreview(mode === "video" ? camera : void 0, effects.effects);
|
|
10225
10500
|
const micStream = useMicrophoneStream(microphone ? mic : "off");
|
|
10226
10501
|
const level = useAudioLevel(micStream);
|
|
10227
|
-
const [speakerTesting, setSpeakerTesting] = (0,
|
|
10228
|
-
(0,
|
|
10502
|
+
const [speakerTesting, setSpeakerTesting] = (0, import_react6.useState)(false);
|
|
10503
|
+
(0, import_react6.useEffect)(() => {
|
|
10229
10504
|
void host.devices.refresh();
|
|
10230
10505
|
}, [host]);
|
|
10231
10506
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mx-meet__prejoin", children: [
|
|
@@ -10341,12 +10616,12 @@ function PreJoinBody({
|
|
|
10341
10616
|
] });
|
|
10342
10617
|
}
|
|
10343
10618
|
function useCameraPreview(deviceId2, effects) {
|
|
10344
|
-
const [preview, setPreview] = (0,
|
|
10345
|
-
const [error, setError] = (0,
|
|
10346
|
-
const current = (0,
|
|
10347
|
-
const initialEffect = (0,
|
|
10619
|
+
const [preview, setPreview] = (0, import_react6.useState)(null);
|
|
10620
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
10621
|
+
const current = (0, import_react6.useRef)(null);
|
|
10622
|
+
const initialEffect = (0, import_react6.useRef)(toVideoEffect(effects));
|
|
10348
10623
|
initialEffect.current = toVideoEffect(effects);
|
|
10349
|
-
(0,
|
|
10624
|
+
(0, import_react6.useEffect)(() => {
|
|
10350
10625
|
if (deviceId2 === void 0) return void 0;
|
|
10351
10626
|
let live = true;
|
|
10352
10627
|
setError(null);
|
|
@@ -10432,16 +10707,16 @@ function MeetingRoomBody({
|
|
|
10432
10707
|
const isHost = useIsHost();
|
|
10433
10708
|
const elapsed = useElapsed(snapshot?.meeting?.startedAt ?? null);
|
|
10434
10709
|
const phase = snapshot?.phase ?? "idle";
|
|
10435
|
-
(0,
|
|
10710
|
+
(0, import_react6.useEffect)(() => {
|
|
10436
10711
|
host.meetings.watch(roomName);
|
|
10437
10712
|
}, [host, roomName]);
|
|
10438
|
-
(0,
|
|
10713
|
+
(0, import_react6.useEffect)(() => {
|
|
10439
10714
|
if (given === void 0) return;
|
|
10440
10715
|
if (host.store.snapshot().meeting !== null) return;
|
|
10441
10716
|
host.store.patch({ meeting: given, locked: given.locked });
|
|
10442
10717
|
}, [host, given]);
|
|
10443
10718
|
const watchedId = meetingId ?? snapshot?.meeting?.id ?? null;
|
|
10444
|
-
(0,
|
|
10719
|
+
(0, import_react6.useEffect)(() => {
|
|
10445
10720
|
if (watchedId === null) return;
|
|
10446
10721
|
host.meetings.watchMeeting(asMeetingId(watchedId));
|
|
10447
10722
|
}, [host, watchedId]);
|
|
@@ -10486,8 +10761,8 @@ function MeetingRoomBody({
|
|
|
10486
10761
|
] });
|
|
10487
10762
|
}
|
|
10488
10763
|
function WaitingRoom({ roomName, host }) {
|
|
10489
|
-
const knocked = (0,
|
|
10490
|
-
(0,
|
|
10764
|
+
const knocked = (0, import_react6.useRef)(false);
|
|
10765
|
+
(0, import_react6.useEffect)(() => {
|
|
10491
10766
|
if (knocked.current) return;
|
|
10492
10767
|
knocked.current = true;
|
|
10493
10768
|
host.meetings.knock(roomName);
|
|
@@ -10506,7 +10781,7 @@ function HostMenu() {
|
|
|
10506
10781
|
const host = useRequiredMeetHost();
|
|
10507
10782
|
const snapshot = useMeetSnapshot();
|
|
10508
10783
|
const end = useEndMeeting();
|
|
10509
|
-
const [confirmingEnd, setConfirmingEnd] = (0,
|
|
10784
|
+
const [confirmingEnd, setConfirmingEnd] = (0, import_react6.useState)(false);
|
|
10510
10785
|
const locked = snapshot?.locked === true;
|
|
10511
10786
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mx-meet__host-menu", children: [
|
|
10512
10787
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -10612,13 +10887,13 @@ function ScheduleMeetingBody({
|
|
|
10612
10887
|
onScheduled,
|
|
10613
10888
|
host
|
|
10614
10889
|
}) {
|
|
10615
|
-
const [title, setTitle] = (0,
|
|
10616
|
-
const [when2, setWhen] = (0,
|
|
10617
|
-
const [kind, setKind] = (0,
|
|
10618
|
-
const [busy, setBusy] = (0,
|
|
10619
|
-
const [link, setLink] = (0,
|
|
10620
|
-
const [error, setError] = (0,
|
|
10621
|
-
const disabled = (0,
|
|
10890
|
+
const [title, setTitle] = (0, import_react6.useState)("");
|
|
10891
|
+
const [when2, setWhen] = (0, import_react6.useState)("");
|
|
10892
|
+
const [kind, setKind] = (0, import_react6.useState)("scheduled");
|
|
10893
|
+
const [busy, setBusy] = (0, import_react6.useState)(false);
|
|
10894
|
+
const [link, setLink] = (0, import_react6.useState)(null);
|
|
10895
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
10896
|
+
const disabled = (0, import_react6.useMemo)(() => title.trim().length === 0 || busy, [title, busy]);
|
|
10622
10897
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
10623
10898
|
"form",
|
|
10624
10899
|
{
|
|
@@ -10755,8 +11030,8 @@ function MeetingRecordBody({
|
|
|
10755
11030
|
}) {
|
|
10756
11031
|
const host = useRequiredMeetHost();
|
|
10757
11032
|
const record = useMeetingRecord(meeting);
|
|
10758
|
-
const [question, setQuestion] = (0,
|
|
10759
|
-
const [tab, setTab] = (0,
|
|
11033
|
+
const [question, setQuestion] = (0, import_react6.useState)("");
|
|
11034
|
+
const [tab, setTab] = (0, import_react6.useState)("summary");
|
|
10760
11035
|
if (record.failure !== null) {
|
|
10761
11036
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mx-meet mx-meet--record", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system.ErrorBox, { as: "div", className: "mx-meet__empty", error: record.failure, operation: "Open this meeting record", origin: "meet/components", children: [
|
|
10762
11037
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "mx-meet__empty-title", children: "This meeting record could not be opened" }),
|
|
@@ -11011,10 +11286,10 @@ function RecordingPlayer(props) {
|
|
|
11011
11286
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RecordingPlayerBody, { ...props, host });
|
|
11012
11287
|
}
|
|
11013
11288
|
function RecordingPlayerBody({ fileId, host }) {
|
|
11014
|
-
const [media, setMedia] = (0,
|
|
11015
|
-
const [loading, setLoading] = (0,
|
|
11016
|
-
const [error, setError] = (0,
|
|
11017
|
-
(0,
|
|
11289
|
+
const [media, setMedia] = (0, import_react6.useState)(null);
|
|
11290
|
+
const [loading, setLoading] = (0, import_react6.useState)(false);
|
|
11291
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
11292
|
+
(0, import_react6.useEffect)(() => {
|
|
11018
11293
|
if (media === null || media.kind !== "bytes") return void 0;
|
|
11019
11294
|
const url = media.url;
|
|
11020
11295
|
return () => URL.revokeObjectURL(url);
|