From 82d918d568aa7e114d59507ad21324d761544d17 Mon Sep 17 00:00:00 2001 From: JF-Cozy Date: Wed, 6 Dec 2023 10:56:43 +0100 Subject: [PATCH] feat(ActionsMenu): Add print action --- react/ActionsMenu/Actions/helpers.js | 20 ++++++ react/ActionsMenu/Actions/helpers.spec.js | 20 +++++- react/ActionsMenu/Actions/index.js | 1 + react/ActionsMenu/Actions/print.js | 67 +++++++++++++++++++ react/ActionsMenu/Readme.md | 4 +- .../ActionMenu/Actions/locales/en.json | 1 + .../ActionMenu/Actions/locales/fr.json | 1 + 7 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 react/ActionsMenu/Actions/print.js diff --git a/react/ActionsMenu/Actions/helpers.js b/react/ActionsMenu/Actions/helpers.js index e027a0b7cb..282880078c 100644 --- a/react/ActionsMenu/Actions/helpers.js +++ b/react/ActionsMenu/Actions/helpers.js @@ -61,3 +61,23 @@ export const getOnlyNeededActions = (actions, file) => { }) ) } + +/** + * Make a base64 string from a File object + * @param {File} file - File object + * @returns {Promise} base64 string + */ +export const makeBase64FromFile = async file => { + const reader = new FileReader() + reader.readAsDataURL(file) + + return new Promise((resolve, reject) => { + reader.onload = () => { + const base64 = reader.result + resolve(base64) + } + reader.onerror = err => { + reject(err) + } + }) +} diff --git a/react/ActionsMenu/Actions/helpers.spec.js b/react/ActionsMenu/Actions/helpers.spec.js index 7197689ec8..506049f5d1 100644 --- a/react/ActionsMenu/Actions/helpers.spec.js +++ b/react/ActionsMenu/Actions/helpers.spec.js @@ -1,4 +1,4 @@ -import { makeActions } from './helpers' +import { makeActions, makeBase64FromFile } from './helpers' describe('makeActions', () => { it('should have empty actions array', () => { @@ -60,3 +60,21 @@ describe('makeActions', () => { expect(actions).toStrictEqual([{ mockConstructor: { propA: 0, propB: 1 } }]) }) }) + +describe('makeBase64FromFile', () => { + it('returns a base64 string for a given file', async () => { + const file = new File(['test'], 'test.txt', { type: 'text/plain' }) + const base64String = await makeBase64FromFile(file) + + expect(base64String).toMatch( + /^data:text\/plain;base64,[a-zA-Z0-9+/]+={0,2}$/ + ) + }) + + it('rejects with an error if the file cannot be read', async () => { + const file = new File(['test'], 'test.txt', { type: 'text/plain' }) + const invalidFile = { ...file, size: -1 } + + await expect(makeBase64FromFile(invalidFile)).rejects.toThrow() + }) +}) diff --git a/react/ActionsMenu/Actions/index.js b/react/ActionsMenu/Actions/index.js index a4ad0c149c..f592ff2eef 100644 --- a/react/ActionsMenu/Actions/index.js +++ b/react/ActionsMenu/Actions/index.js @@ -4,4 +4,5 @@ export { modify } from './modify' export { smsTo } from './smsTo' export { call } from './call' export { emailTo } from './emailTo' +export { print } from './print' export { viewInContacts } from './viewInContacts' diff --git a/react/ActionsMenu/Actions/print.js b/react/ActionsMenu/Actions/print.js new file mode 100644 index 0000000000..e4271f2f1b --- /dev/null +++ b/react/ActionsMenu/Actions/print.js @@ -0,0 +1,67 @@ +import React, { forwardRef } from 'react' + +import logger from 'cozy-logger' +import { useWebviewIntent } from 'cozy-intent' +import { fetchBlobFileById } from 'cozy-client/dist/models/file' + +import { makeBase64FromFile } from './helpers' +import PrinterIcon from '../../Icons/Printer' +import withActionsLocales from './locales/withActionsLocales' +import ActionsMenuItem from '../ActionsMenuItem' +import ListItemIcon from '../../ListItemIcon' +import Icon from '../../Icon' +import ListItemText from '../../ListItemText' +import { useI18n } from '../../providers/I18n' + +export const print = () => { + return { + name: 'print', + action: async (doc, { client, webviewIntent }) => { + if (webviewIntent) { + try { + const blob = await fetchBlobFileById(client, doc._id) + const base64 = await makeBase64FromFile(blob) + + return webviewIntent.call('print', base64) + } catch (error) { + logger.error( + `Error trying to print document with Flagship App: ${JSON.stringify( + error + )}` + ) + } + } + + try { + const downloadURL = await client + .collection('io.cozy.files') + .getDownloadLinkById(doc._id, doc.name) + + window.open(downloadURL, '_blank') + } catch (error) { + logger.error(`Error trying to print document: ${JSON.stringify(error)}`) + } + }, + Component: withActionsLocales( + forwardRef(({ onClick, ...props }, ref) => { + const { t } = useI18n() + const webviewIntent = useWebviewIntent() + + return ( + { + onClick({ webviewIntent }) + }} + > + + + + + + ) + }) + ) + } +} diff --git a/react/ActionsMenu/Readme.md b/react/ActionsMenu/Readme.md index 80912429fb..8e9b43298e 100644 --- a/react/ActionsMenu/Readme.md +++ b/react/ActionsMenu/Readme.md @@ -52,7 +52,7 @@ import Icon from 'cozy-ui/transpiled/react/Icon' import FileTypeText from 'cozy-ui/transpiled/react/Icons/FileTypeText' import FileIcon from 'cozy-ui/transpiled/react/Icons/File' -import { makeActions, modify, emailTo, viewInContacts, divider, smsTo, call } from 'cozy-ui/transpiled/react/ActionsMenu/Actions' +import { makeActions, modify, emailTo, print, viewInContacts, divider, smsTo, call } from 'cozy-ui/transpiled/react/ActionsMenu/Actions' initialState = { showMenu: isTesting() } @@ -87,7 +87,7 @@ const customAction = () => ({ }) }) -const actions = makeActions([ modify, viewInContacts, divider, call, smsTo, emailTo, divider, customAction ]) +const actions = makeActions([ modify, viewInContacts, divider, call, smsTo, emailTo, print, divider, customAction ]) ; diff --git a/react/deprecated/ActionMenu/Actions/locales/en.json b/react/deprecated/ActionMenu/Actions/locales/en.json index 3eb6ab6ea4..b83566aa9c 100644 --- a/react/deprecated/ActionMenu/Actions/locales/en.json +++ b/react/deprecated/ActionMenu/Actions/locales/en.json @@ -3,5 +3,6 @@ "modify": "Modify", "emailTo": "Send an email", "smsTo": "Send a message", + "print": "Print", "call": "Call" } diff --git a/react/deprecated/ActionMenu/Actions/locales/fr.json b/react/deprecated/ActionMenu/Actions/locales/fr.json index 9991677673..b16813f44d 100644 --- a/react/deprecated/ActionMenu/Actions/locales/fr.json +++ b/react/deprecated/ActionMenu/Actions/locales/fr.json @@ -3,5 +3,6 @@ "modify": "Modifier", "emailTo": "Envoyer un e-mail", "smsTo": "Envoyer un message", + "print": "Imprimer", "call": "Appeler" }