2017-10-12 10:00:28 +08:00
|
|
|
import Presentations from '/imports/api/presentations';
|
2022-07-22 21:06:32 +08:00
|
|
|
import React from 'react';
|
|
|
|
import Icon from '/imports/ui/components/common/icon/component';
|
2018-09-05 00:56:10 +08:00
|
|
|
import PresentationUploadToken from '/imports/api/presentation-upload-token';
|
2017-05-04 00:36:16 +08:00
|
|
|
import Auth from '/imports/ui/services/auth';
|
2019-03-09 04:46:25 +08:00
|
|
|
import Poll from '/imports/api/polls/';
|
2022-07-22 02:56:44 +08:00
|
|
|
import { Meteor } from 'meteor/meteor';
|
|
|
|
import { defineMessages, injectIntl } from 'react-intl';
|
2017-09-27 03:45:33 +08:00
|
|
|
import { makeCall } from '/imports/ui/services/api';
|
2020-04-30 00:34:37 +08:00
|
|
|
import logger from '/imports/startup/client/logger';
|
2022-07-22 21:06:32 +08:00
|
|
|
import Styled from './styles';
|
|
|
|
import { toast } from 'react-toastify';
|
2017-11-28 20:26:00 +08:00
|
|
|
import _ from 'lodash';
|
2022-04-08 22:28:47 +08:00
|
|
|
import { Random } from 'meteor/random'
|
2017-05-04 00:36:16 +08:00
|
|
|
|
2017-09-27 03:45:33 +08:00
|
|
|
const CONVERSION_TIMEOUT = 300000;
|
2018-09-05 00:56:10 +08:00
|
|
|
const TOKEN_TIMEOUT = 5000;
|
2022-07-22 02:56:44 +08:00
|
|
|
const PRESENTATION_CONFIG = Meteor.settings.public.presentation;
|
|
|
|
|
|
|
|
const intlMessages = defineMessages({
|
|
|
|
|
|
|
|
item: {
|
|
|
|
id: 'app.presentationUploder.item',
|
|
|
|
description: 'single item label',
|
|
|
|
},
|
|
|
|
itemPlural: {
|
|
|
|
id: 'app.presentationUploder.itemPlural',
|
|
|
|
description: 'plural item label',
|
|
|
|
},
|
|
|
|
uploading: {
|
|
|
|
id: 'app.presentationUploder.uploading',
|
|
|
|
description: 'uploading label for toast notification',
|
|
|
|
},
|
|
|
|
uploadStatus: {
|
|
|
|
id: 'app.presentationUploder.uploadStatus',
|
|
|
|
description: 'upload status for toast notification',
|
|
|
|
},
|
|
|
|
completed: {
|
|
|
|
id: 'app.presentationUploder.completed',
|
|
|
|
description: 'uploads complete label for toast notification',
|
|
|
|
},
|
|
|
|
GENERATING_THUMBNAIL: {
|
|
|
|
id: 'app.presentationUploder.conversion.generatingThumbnail',
|
|
|
|
description: 'indicatess that it is generating thumbnails',
|
|
|
|
},
|
|
|
|
GENERATING_SVGIMAGES: {
|
|
|
|
id: 'app.presentationUploder.conversion.generatingSvg',
|
|
|
|
description: 'warns that it is generating svg images',
|
|
|
|
},
|
|
|
|
GENERATED_SLIDE: {
|
|
|
|
id: 'app.presentationUploder.conversion.generatedSlides',
|
|
|
|
description: 'warns that were slides generated',
|
|
|
|
},
|
|
|
|
PAGE_COUNT_EXCEEDED: {
|
|
|
|
id: 'app.presentationUploder.conversion.pageCountExceeded',
|
|
|
|
description: 'warns the user that the conversion failed because of the page count',
|
|
|
|
},
|
|
|
|
PDF_HAS_BIG_PAGE: {
|
|
|
|
id: 'app.presentationUploder.conversion.pdfHasBigPage',
|
|
|
|
description: 'warns the user that the conversion failed because of the pdf page siz that exceeds the allowed limit',
|
|
|
|
},
|
|
|
|
OFFICE_DOC_CONVERSION_INVALID: {
|
|
|
|
id: 'app.presentationUploder.conversion.officeDocConversionInvalid',
|
|
|
|
description: '',
|
|
|
|
},
|
|
|
|
OFFICE_DOC_CONVERSION_FAILED: {
|
|
|
|
id: 'app.presentationUploder.conversion.officeDocConversionFailed',
|
|
|
|
description: 'warns the user that the conversion failed because of wrong office file',
|
|
|
|
},
|
|
|
|
UNSUPPORTED_DOCUMENT: {
|
|
|
|
id: 'app.presentationUploder.conversion.unsupportedDocument',
|
|
|
|
description: 'warns the user that the file extension is not supported',
|
|
|
|
},
|
|
|
|
fileToUpload: {
|
|
|
|
id: 'app.presentationUploder.fileToUpload',
|
|
|
|
description: 'message used in the file selected for upload',
|
|
|
|
},
|
|
|
|
uploadProcess: {
|
|
|
|
id: 'app.presentationUploder.upload.progress',
|
|
|
|
description: 'message that indicates the percentage of the upload',
|
|
|
|
},
|
|
|
|
badConnectionError: {
|
|
|
|
id: 'app.presentationUploder.connectionClosedError',
|
|
|
|
description: 'message indicating that the connection was closed',
|
|
|
|
},
|
|
|
|
conversionProcessingSlides: {
|
|
|
|
id: 'app.presentationUploder.conversion.conversionProcessingSlides',
|
|
|
|
description: 'indicates how many slides were converted',
|
|
|
|
},
|
|
|
|
genericError: {
|
|
|
|
id: 'app.presentationUploder.genericError',
|
|
|
|
description: 'generic error while uploading/converting',
|
|
|
|
},
|
|
|
|
genericConversionStatus: {
|
|
|
|
id: 'app.presentationUploder.conversion.genericConversionStatus',
|
|
|
|
description: 'indicates that file is being converted',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2017-09-27 03:45:33 +08:00
|
|
|
|
2019-02-21 06:20:04 +08:00
|
|
|
// fetch doesn't support progress. So we use xhr which support progress.
|
2017-09-08 02:18:14 +08:00
|
|
|
const futch = (url, opts = {}, onProgress) => new Promise((res, rej) => {
|
|
|
|
const xhr = new XMLHttpRequest();
|
|
|
|
|
|
|
|
xhr.open(opts.method || 'get', url);
|
|
|
|
|
|
|
|
Object.keys(opts.headers || {})
|
|
|
|
.forEach(k => xhr.setRequestHeader(k, opts.headers[k]));
|
|
|
|
|
|
|
|
xhr.onload = (e) => {
|
|
|
|
if (e.target.status !== 200) {
|
|
|
|
return rej({ code: e.target.status, message: e.target.statusText });
|
|
|
|
}
|
|
|
|
|
|
|
|
return res(e.target.responseText);
|
|
|
|
};
|
|
|
|
xhr.onerror = rej;
|
|
|
|
if (xhr.upload && onProgress) {
|
|
|
|
xhr.upload.addEventListener('progress', onProgress, false);
|
|
|
|
}
|
|
|
|
xhr.send(opts.body);
|
|
|
|
});
|
|
|
|
|
2019-03-19 02:13:15 +08:00
|
|
|
const getPresentations = () => Presentations
|
|
|
|
.find({
|
|
|
|
'conversion.error': false,
|
|
|
|
})
|
|
|
|
.fetch()
|
|
|
|
.map((presentation) => {
|
|
|
|
const {
|
|
|
|
conversion,
|
|
|
|
current,
|
|
|
|
downloadable,
|
2022-02-03 22:37:14 +08:00
|
|
|
removable,
|
2019-03-19 02:13:15 +08:00
|
|
|
id,
|
|
|
|
name,
|
|
|
|
} = presentation;
|
|
|
|
|
|
|
|
const uploadTimestamp = id.split('-').pop();
|
|
|
|
|
|
|
|
return {
|
|
|
|
id,
|
|
|
|
filename: name,
|
|
|
|
isCurrent: current || false,
|
2017-09-08 02:18:14 +08:00
|
|
|
upload: { done: true, error: false },
|
2019-03-19 02:13:15 +08:00
|
|
|
isDownloadable: downloadable,
|
2022-02-03 22:37:14 +08:00
|
|
|
isRemovable: removable,
|
2019-03-19 02:13:15 +08:00
|
|
|
conversion: conversion || { done: true, error: false },
|
|
|
|
uploadTimestamp,
|
|
|
|
};
|
|
|
|
});
|
2017-05-04 00:36:16 +08:00
|
|
|
|
2019-02-21 06:20:04 +08:00
|
|
|
const dispatchTogglePresentationDownloadable = (presentation, newState) => {
|
|
|
|
makeCall('setPresentationDownloadable', presentation.id, newState);
|
|
|
|
};
|
|
|
|
|
2019-07-12 01:46:44 +08:00
|
|
|
const observePresentationConversion = (
|
|
|
|
meetingId,
|
2022-03-15 01:46:51 +08:00
|
|
|
tmpPresId,
|
2019-07-12 01:46:44 +08:00
|
|
|
onConversion,
|
|
|
|
) => new Promise((resolve) => {
|
|
|
|
const conversionTimeout = setTimeout(() => {
|
|
|
|
onConversion({
|
|
|
|
done: true,
|
|
|
|
error: true,
|
|
|
|
status: 'TIMEOUT',
|
|
|
|
});
|
|
|
|
}, CONVERSION_TIMEOUT);
|
|
|
|
|
|
|
|
const didValidate = (doc) => {
|
|
|
|
clearTimeout(conversionTimeout);
|
|
|
|
resolve(doc);
|
|
|
|
};
|
2017-11-28 01:44:45 +08:00
|
|
|
|
2019-07-12 01:46:44 +08:00
|
|
|
Tracker.autorun((c) => {
|
|
|
|
const query = Presentations.find({ meetingId });
|
2017-09-27 03:45:33 +08:00
|
|
|
|
2019-07-12 01:46:44 +08:00
|
|
|
query.observe({
|
2021-04-21 01:21:12 +08:00
|
|
|
added: (doc) => {
|
2022-03-15 01:46:51 +08:00
|
|
|
if (doc.temporaryPresentationId !== tmpPresId) return;
|
2021-04-21 01:21:12 +08:00
|
|
|
|
2021-04-28 03:45:14 +08:00
|
|
|
if (doc.conversion.status === 'FILE_TOO_LARGE' || doc.conversion.status === 'UNSUPPORTED_DOCUMENT') {
|
2021-04-21 01:21:12 +08:00
|
|
|
onConversion(doc.conversion);
|
|
|
|
c.stop();
|
|
|
|
clearTimeout(conversionTimeout);
|
|
|
|
}
|
|
|
|
},
|
2019-07-12 01:46:44 +08:00
|
|
|
changed: (newDoc) => {
|
2022-03-15 01:46:51 +08:00
|
|
|
if (newDoc.temporaryPresentationId !== tmpPresId) return;
|
2017-09-27 03:45:33 +08:00
|
|
|
|
2019-07-12 01:46:44 +08:00
|
|
|
onConversion(newDoc.conversion);
|
2017-11-28 01:44:45 +08:00
|
|
|
|
2021-04-21 01:21:12 +08:00
|
|
|
if (newDoc.conversion.error) {
|
|
|
|
c.stop();
|
|
|
|
clearTimeout(conversionTimeout);
|
|
|
|
}
|
|
|
|
|
2019-07-12 01:46:44 +08:00
|
|
|
if (newDoc.conversion.done) {
|
|
|
|
c.stop();
|
|
|
|
didValidate(newDoc);
|
|
|
|
}
|
|
|
|
},
|
2017-09-27 03:45:33 +08:00
|
|
|
});
|
|
|
|
});
|
2019-07-12 01:46:44 +08:00
|
|
|
});
|
2017-09-27 03:45:33 +08:00
|
|
|
|
2019-07-12 01:46:44 +08:00
|
|
|
const requestPresentationUploadToken = (
|
2022-03-15 01:46:51 +08:00
|
|
|
tmpPresId,
|
2019-07-12 01:46:44 +08:00
|
|
|
podId,
|
|
|
|
meetingId,
|
|
|
|
filename,
|
|
|
|
) => new Promise((resolve, reject) => {
|
2022-03-15 01:46:51 +08:00
|
|
|
makeCall('requestPresentationUploadToken', podId, filename, tmpPresId);
|
2019-07-12 01:46:44 +08:00
|
|
|
|
|
|
|
let computation = null;
|
|
|
|
const timeout = setTimeout(() => {
|
|
|
|
computation.stop();
|
|
|
|
reject({ code: 408, message: 'requestPresentationUploadToken timeout' });
|
|
|
|
}, TOKEN_TIMEOUT);
|
|
|
|
|
|
|
|
Tracker.autorun((c) => {
|
|
|
|
computation = c;
|
2022-03-15 01:46:51 +08:00
|
|
|
const sub = Meteor.subscribe('presentation-upload-token', podId, filename, tmpPresId);
|
2019-07-12 01:46:44 +08:00
|
|
|
if (!sub.ready()) return;
|
|
|
|
|
|
|
|
const PresentationToken = PresentationUploadToken.findOne({
|
|
|
|
podId,
|
|
|
|
meetingId,
|
2022-03-15 01:46:51 +08:00
|
|
|
tmpPresId,
|
2019-07-12 01:46:44 +08:00
|
|
|
used: false,
|
2018-09-05 00:56:10 +08:00
|
|
|
});
|
2019-07-12 01:46:44 +08:00
|
|
|
|
|
|
|
if (!PresentationToken || !('failed' in PresentationToken)) return;
|
|
|
|
|
|
|
|
if (!PresentationToken.failed) {
|
|
|
|
clearTimeout(timeout);
|
|
|
|
resolve(PresentationToken.authzToken);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PresentationToken.failed) {
|
2019-07-19 02:45:11 +08:00
|
|
|
reject({ code: 401, message: `requestPresentationUploadToken token ${PresentationToken.authzToken} failed` });
|
2019-07-12 01:46:44 +08:00
|
|
|
}
|
2018-09-05 00:56:10 +08:00
|
|
|
});
|
2019-07-12 01:46:44 +08:00
|
|
|
});
|
2018-09-05 00:56:10 +08:00
|
|
|
|
2019-07-12 01:46:44 +08:00
|
|
|
const uploadAndConvertPresentation = (
|
|
|
|
file,
|
|
|
|
downloadable,
|
|
|
|
podId,
|
|
|
|
meetingId,
|
|
|
|
endpoint,
|
|
|
|
onUpload,
|
|
|
|
onProgress,
|
|
|
|
onConversion,
|
|
|
|
) => {
|
2022-04-08 22:28:47 +08:00
|
|
|
const tmpPresId = _.uniqueId(Random.id(20))
|
|
|
|
|
2017-06-07 20:28:41 +08:00
|
|
|
const data = new FormData();
|
2017-05-04 00:36:16 +08:00
|
|
|
data.append('fileUpload', file);
|
2018-09-05 00:56:10 +08:00
|
|
|
data.append('conference', meetingId);
|
|
|
|
data.append('room', meetingId);
|
2022-03-26 01:12:10 +08:00
|
|
|
data.append('temporaryPresentationId', tmpPresId);
|
2018-09-05 00:56:10 +08:00
|
|
|
|
|
|
|
// TODO: Currently the uploader is not related to a POD so the id is fixed to the default
|
|
|
|
data.append('pod_id', podId);
|
|
|
|
|
2019-02-23 05:04:35 +08:00
|
|
|
data.append('is_downloadable', downloadable);
|
2017-05-04 00:36:16 +08:00
|
|
|
|
2017-09-08 02:18:14 +08:00
|
|
|
const opts = {
|
2017-05-04 00:36:16 +08:00
|
|
|
method: 'POST',
|
|
|
|
body: data,
|
2017-09-08 02:18:14 +08:00
|
|
|
};
|
|
|
|
|
2022-03-15 01:46:51 +08:00
|
|
|
return requestPresentationUploadToken(tmpPresId, podId, meetingId, file.name)
|
2019-07-12 01:46:44 +08:00
|
|
|
.then((token) => {
|
|
|
|
makeCall('setUsedToken', token);
|
|
|
|
return futch(endpoint.replace('upload', `${token}/upload`), opts, onProgress);
|
|
|
|
})
|
2022-03-15 01:46:51 +08:00
|
|
|
.then(() => observePresentationConversion(meetingId, tmpPresId, onConversion))
|
2017-09-27 03:45:33 +08:00
|
|
|
// Trap the error so we can have parallel upload
|
|
|
|
.catch((error) => {
|
2020-04-30 00:34:37 +08:00
|
|
|
logger.debug({
|
|
|
|
logCode: 'presentation_uploader_service',
|
|
|
|
extraInfo: {
|
|
|
|
error,
|
|
|
|
},
|
|
|
|
}, 'Generic presentation upload exception catcher');
|
2022-03-15 01:46:51 +08:00
|
|
|
observePresentationConversion(meetingId, tmpPresId, onConversion);
|
2017-11-28 01:44:45 +08:00
|
|
|
onUpload({ error: true, done: true, status: error.code });
|
|
|
|
return Promise.resolve();
|
2017-09-27 03:45:33 +08:00
|
|
|
});
|
2017-05-04 00:36:16 +08:00
|
|
|
};
|
|
|
|
|
2019-07-12 01:46:44 +08:00
|
|
|
const uploadAndConvertPresentations = (
|
|
|
|
presentationsToUpload,
|
|
|
|
meetingId,
|
|
|
|
podId,
|
|
|
|
uploadEndpoint,
|
2021-04-21 01:21:12 +08:00
|
|
|
) => Promise.all(presentationsToUpload.map((p) => uploadAndConvertPresentation(
|
2022-04-08 22:28:47 +08:00
|
|
|
p.file, p.isDownloadable, podId, meetingId, uploadEndpoint,
|
2019-07-12 01:46:44 +08:00
|
|
|
p.onUpload, p.onProgress, p.onConversion,
|
|
|
|
)));
|
2017-05-04 04:51:17 +08:00
|
|
|
|
2020-01-25 09:02:36 +08:00
|
|
|
const setPresentation = (presentationId, podId) => {
|
|
|
|
makeCall('setPresentation', presentationId, podId);
|
|
|
|
};
|
2017-09-30 01:44:18 +08:00
|
|
|
|
2019-03-09 04:46:25 +08:00
|
|
|
const removePresentation = (presentationId, podId) => {
|
2019-08-22 20:05:06 +08:00
|
|
|
const hasPoll = Poll.find({}, { fields: {} }).count();
|
2019-03-09 04:46:25 +08:00
|
|
|
if (hasPoll) makeCall('stopPoll');
|
|
|
|
makeCall('removePresentation', presentationId, podId);
|
|
|
|
};
|
2017-05-04 04:51:17 +08:00
|
|
|
|
2019-07-12 01:46:44 +08:00
|
|
|
const removePresentations = (
|
|
|
|
presentationsToRemove,
|
|
|
|
podId,
|
2021-04-21 01:21:12 +08:00
|
|
|
) => Promise.all(presentationsToRemove.map((p) => removePresentation(p.id, podId)));
|
2017-05-04 00:36:16 +08:00
|
|
|
|
2022-07-22 02:56:44 +08:00
|
|
|
function renderPresentationItemStatus(item, intl) {
|
|
|
|
if (!item.upload.done && item.upload.progress === 0) {
|
|
|
|
return intl.formatMessage(intlMessages.fileToUpload);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!item.upload.done && !item.upload.error) {
|
|
|
|
return intl.formatMessage(intlMessages.uploadProcess, {
|
|
|
|
0: Math.floor(item.upload.progress).toString(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
const constraint = {};
|
|
|
|
|
|
|
|
if (item.upload.done && item.upload.error) {
|
|
|
|
if (item.conversion.status === 'FILE_TOO_LARGE') {
|
|
|
|
constraint['0'] = ((item.conversion.maxFileSize) / 1000 / 1000).toFixed(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (item.upload.progress < 100) {
|
|
|
|
const errorMessage = intlMessages.badConnectionError;
|
|
|
|
return intl.formatMessage(errorMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
const errorMessage = intlMessages[item.upload.status] || intlMessages.genericError;
|
|
|
|
return intl.formatMessage(errorMessage, constraint);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!item.conversion.done && item.conversion.error) {
|
|
|
|
const errorMessage = intlMessages[item.conversion.status] || intlMessages.genericConversionStatus;
|
|
|
|
|
|
|
|
switch (item.conversion.status) {
|
|
|
|
case 'PAGE_COUNT_EXCEEDED':
|
|
|
|
constraint['0'] = item.conversion.maxNumberPages;
|
|
|
|
break;
|
|
|
|
case 'PDF_HAS_BIG_PAGE':
|
|
|
|
constraint['0'] = (item.conversion.bigPageSize / 1000 / 1000).toFixed(2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return intl.formatMessage(errorMessage, constraint);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!item.conversion.done && !item.conversion.error) {
|
|
|
|
if (item.conversion.pagesCompleted < item.conversion.numPages) {
|
|
|
|
return intl.formatMessage(intlMessages.conversionProcessingSlides, {
|
|
|
|
0: item.conversion.pagesCompleted,
|
|
|
|
1: item.conversion.numPages,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
const conversionStatusMessage = intlMessages[item.conversion.status]
|
|
|
|
|| intlMessages.genericConversionStatus;
|
|
|
|
return intl.formatMessage(conversionStatusMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderToastItem(item, intl) {
|
|
|
|
const isUploading = !item.upload.done && item.upload.progress > 0;
|
|
|
|
const isConverting = !item.conversion.done && item.upload.done;
|
|
|
|
const hasError = item.conversion.error || item.upload.error;
|
|
|
|
const isProcessing = (isUploading || isConverting) && !hasError;
|
|
|
|
|
|
|
|
let icon = isProcessing ? 'blank' : 'check';
|
|
|
|
if (hasError) icon = 'circle_close';
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Styled.UploadRow
|
|
|
|
key={item.id}
|
|
|
|
onClick={() => {
|
|
|
|
if (hasError || isProcessing) Session.set('showUploadPresentationView', true);
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Styled.FileLine>
|
|
|
|
<span>
|
|
|
|
<Icon iconName="file" />
|
|
|
|
</span>
|
|
|
|
<Styled.ToastFileName>
|
|
|
|
<span>{item.filename}</span>
|
|
|
|
</Styled.ToastFileName>
|
|
|
|
<Styled.StatusIcon>
|
|
|
|
<Styled.ToastItemIcon
|
|
|
|
done={!isProcessing && !hasError}
|
|
|
|
error={hasError}
|
|
|
|
loading={isProcessing}
|
|
|
|
iconName={icon}
|
|
|
|
/>
|
|
|
|
</Styled.StatusIcon>
|
|
|
|
</Styled.FileLine>
|
|
|
|
<Styled.StatusInfo>
|
|
|
|
<Styled.StatusInfoSpan data-test="presentationStatusInfo" styles={hasError ? 'error' : 'info'}>
|
|
|
|
{renderPresentationItemStatus(item, intl)}
|
|
|
|
</Styled.StatusInfoSpan>
|
|
|
|
</Styled.StatusInfo>
|
|
|
|
</Styled.UploadRow>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-07-26 20:25:36 +08:00
|
|
|
const verifyUploadToast = (presentations, toUploadCount, intl) => {
|
|
|
|
const toastId = Session.get("presentationUploaderToastId");
|
|
|
|
|
|
|
|
if (toastId) {
|
|
|
|
toast.update(toastId, {
|
|
|
|
render: renderToastList(presentations, toUploadCount, intl),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const observePresentationsForToast = (meetingId, presentations, toUploadCount, intl) => new Promise((resolve, reject) => {
|
|
|
|
|
|
|
|
Tracker.autorun((c) => {
|
|
|
|
const query = Presentations.find({ meetingId });
|
|
|
|
|
|
|
|
query.observe({
|
|
|
|
added: (doc) => {
|
|
|
|
console.log(presentations)
|
|
|
|
verifyUploadToast(presentations, toUploadCount, intl)
|
|
|
|
},
|
|
|
|
changed: (newDoc) => {
|
|
|
|
console.log(presentations)
|
|
|
|
verifyUploadToast(presentations, toUploadCount, intl)
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
|
|
|
})
|
|
|
|
|
2022-07-22 21:06:32 +08:00
|
|
|
function handleDismissToast(toastId) {
|
|
|
|
return toast.dismiss(toastId);
|
|
|
|
}
|
|
|
|
|
2022-07-22 02:56:44 +08:00
|
|
|
function renderToastList(presentations, toUploadCount, intl) {
|
|
|
|
|
|
|
|
if (toUploadCount === 0) {
|
2022-07-22 21:06:32 +08:00
|
|
|
const toastId = Session.get("presentationUploaderToastId")
|
|
|
|
return handleDismissToast(toastId);
|
2022-07-22 02:56:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
let converted = 0;
|
|
|
|
|
|
|
|
let presentationsSorted = presentations
|
|
|
|
.filter((p) => (p.upload.progress || p.conversion.status) && p.file)
|
|
|
|
.sort((a, b) => a.uploadTimestamp - b.uploadTimestamp)
|
|
|
|
.sort((a, b) => a.conversion.done - b.conversion.done);
|
|
|
|
|
|
|
|
presentationsSorted = presentationsSorted
|
|
|
|
.splice(0, toUploadCount)
|
|
|
|
.map((p) => {
|
|
|
|
if (p.conversion.done) converted += 1;
|
|
|
|
return p;
|
|
|
|
});
|
|
|
|
|
|
|
|
let toastHeading = '';
|
|
|
|
const itemLabel = presentationsSorted.length > 1
|
|
|
|
? intl.formatMessage(intlMessages.itemPlural)
|
|
|
|
: intl.formatMessage(intlMessages.item);
|
|
|
|
|
|
|
|
if (converted === 0) {
|
|
|
|
toastHeading = intl.formatMessage(intlMessages.uploading, {
|
|
|
|
0: presentationsSorted.length,
|
|
|
|
1: itemLabel,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (converted > 0 && converted !== presentationsSorted.length) {
|
|
|
|
toastHeading = intl.formatMessage(intlMessages.uploadStatus, {
|
|
|
|
0: converted,
|
|
|
|
1: presentationsSorted.length,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (converted === presentationsSorted.length) {
|
|
|
|
toastHeading = intl.formatMessage(intlMessages.completed, {
|
|
|
|
0: converted,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Styled.ToastWrapper>
|
|
|
|
<Styled.UploadToastHeader>
|
|
|
|
<Styled.UploadIcon iconName="upload" />
|
|
|
|
<Styled.UploadToastTitle>{toastHeading}</Styled.UploadToastTitle>
|
|
|
|
</Styled.UploadToastHeader>
|
|
|
|
<Styled.InnerToast>
|
|
|
|
<div>
|
|
|
|
<div>
|
|
|
|
{presentationsSorted.map((item) => renderToastItem(item, intl))}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</Styled.InnerToast>
|
|
|
|
</Styled.ToastWrapper>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-07-22 21:06:32 +08:00
|
|
|
const persistPresentationChanges = (oldState, newState, uploadEndpoint, podId, toUploadCount, intl) => {
|
2021-04-21 01:21:12 +08:00
|
|
|
const presentationsToUpload = newState.filter((p) => !p.upload.done);
|
2022-07-22 21:06:32 +08:00
|
|
|
|
2022-07-22 02:56:44 +08:00
|
|
|
if (presentationsToUpload.length > 0) {
|
|
|
|
console.log("Vou criar toast")
|
2022-07-22 21:06:32 +08:00
|
|
|
const toastId = toast.info(renderToastList(newState, toUploadCount, intl ), {
|
2022-07-22 02:56:44 +08:00
|
|
|
hideProgressBar: true,
|
|
|
|
autoClose: false,
|
|
|
|
newestOnTop: true,
|
|
|
|
closeOnClick: true,
|
|
|
|
onClose: () => {
|
2022-07-22 21:06:32 +08:00
|
|
|
Session.set("presentationUploaderToastId", null)
|
2022-07-22 02:56:44 +08:00
|
|
|
},
|
|
|
|
});
|
2022-07-22 21:06:32 +08:00
|
|
|
Session.set('presentationUploaderToastId', toastId)
|
2022-07-26 20:25:36 +08:00
|
|
|
observePresentationsForToast(Auth.meetingID, presentationsToUpload, toUploadCount, intl)
|
2022-07-22 02:56:44 +08:00
|
|
|
}
|
2021-04-21 01:21:12 +08:00
|
|
|
const presentationsToRemove = oldState.filter((p) => !_.find(newState, ['id', p.id]));
|
2017-11-28 20:26:00 +08:00
|
|
|
|
2021-04-21 01:21:12 +08:00
|
|
|
let currentPresentation = newState.find((p) => p.isCurrent);
|
2017-11-28 01:44:45 +08:00
|
|
|
|
2018-09-05 00:56:10 +08:00
|
|
|
return uploadAndConvertPresentations(presentationsToUpload, Auth.meetingID, podId, uploadEndpoint)
|
2017-11-28 01:44:45 +08:00
|
|
|
.then((presentations) => {
|
|
|
|
if (!presentations.length && !currentPresentation) return Promise.resolve();
|
|
|
|
|
|
|
|
// Update the presentation with their new ids
|
|
|
|
presentations.forEach((p, i) => {
|
|
|
|
if (p === undefined) return;
|
|
|
|
presentationsToUpload[i].onDone(p.id);
|
|
|
|
});
|
|
|
|
|
|
|
|
return Promise.resolve(presentations);
|
|
|
|
})
|
|
|
|
.then((presentations) => {
|
2017-12-16 02:49:47 +08:00
|
|
|
if (currentPresentation === undefined) {
|
2021-08-27 04:13:05 +08:00
|
|
|
setPresentation('', podId);
|
2017-12-16 02:49:47 +08:00
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
|
2017-11-28 01:44:45 +08:00
|
|
|
// If its a newly uploaded presentation we need to get it from promise result
|
|
|
|
if (!currentPresentation.conversion.done) {
|
2021-04-21 01:21:12 +08:00
|
|
|
const currentIndex = presentationsToUpload.findIndex((p) => p === currentPresentation);
|
2017-11-28 01:44:45 +08:00
|
|
|
currentPresentation = presentations[currentIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
// skip setting as current if error happened
|
2017-12-16 02:49:47 +08:00
|
|
|
if (currentPresentation.conversion.error) {
|
2017-11-28 01:44:45 +08:00
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
|
2018-09-05 00:56:10 +08:00
|
|
|
return setPresentation(currentPresentation.id, podId);
|
2017-11-28 01:44:45 +08:00
|
|
|
})
|
2018-09-05 00:56:10 +08:00
|
|
|
.then(removePresentations.bind(null, presentationsToRemove, podId));
|
2017-05-04 00:36:16 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
export default {
|
|
|
|
getPresentations,
|
|
|
|
persistPresentationChanges,
|
2019-02-21 06:20:04 +08:00
|
|
|
dispatchTogglePresentationDownloadable,
|
2020-01-25 09:02:36 +08:00
|
|
|
setPresentation,
|
2022-03-08 23:29:11 +08:00
|
|
|
requestPresentationUploadToken,
|
2022-07-22 21:06:32 +08:00
|
|
|
renderToastList,
|
|
|
|
handleDismissToast,
|
|
|
|
renderPresentationItemStatus,
|
2017-05-04 00:36:16 +08:00
|
|
|
};
|