From 18cd43d0e6a869451a5bc384cdca4759060f8ad0 Mon Sep 17 00:00:00 2001 From: PolariTOON <36267812+PolariTOON@users.noreply.github.com> Date: Wed, 7 Dec 2022 17:25:17 +0100 Subject: [PATCH 1/7] feat: Update `cozy-client` to 34.4.0 `cozy-client` as been upgraded to to `34.4.0` to be able to use paper helpers BREAKING CHANGE: You need to update `cozy-client` to `>34.4.0`. --- package.json | 4 ++-- yarn.lock | 25 ++++++++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index c108522f03..386c612e61 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "babel-preset-cozy-app": "2.0.2", "browserslist-config-cozy": "0.4.0", "copyfiles": "2.4.1", - "cozy-client": "^33.0.0", + "cozy-client": "^34.4.0", "cozy-device-helper": "2.0.0", "cozy-flags": "^2.10.1", "cozy-harvest-lib": "^6.7.3", @@ -179,7 +179,7 @@ "rooks": "^5.11.2" }, "peerDependencies": { - "cozy-client": ">=33.0.0", + "cozy-client": ">=34.4.0", "cozy-device-helper": "^2.0.0", "cozy-harvest-lib": "^6.7.3", "cozy-intent": ">=1.3.0", diff --git a/yarn.lock b/yarn.lock index 55176afb92..0edaf527b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5852,16 +5852,17 @@ cozy-bi-auth@0.0.23: lodash "^4.17.20" node-jose "^1.1.4" -cozy-client@^33.0.0: - version "33.0.0" - resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-33.0.0.tgz#0711096ce281c9ebfe017a95475ceacf7879dd2e" - integrity sha512-RXzjoii+3/ri99EJTJF+ogEvYKW7qQ2VPcmMS5q1UCBOqziXGnDxND/DbHPX6wZaOynSBfJ/iyBIqhlmEi469w== +cozy-client@^34.4.0: + version "34.4.0" + resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-34.4.0.tgz#7d72aa3a38c08de4f3597c5fc68998553dd29f2f" + integrity sha512-Vh50SGKVHaxT1pDlmXn5AtEd8W2dzPFczXLOm4A9HuBttNUzS8cT2/MXfo9Xs7YV7nU/PhPlKtyvdrZqo9RxXQ== dependencies: "@cozy/minilog" "1.0.0" "@types/jest" "^26.0.20" "@types/lodash" "^4.14.170" btoa "^1.2.1" - cozy-stack-client "^33.0.0" + cozy-stack-client "^34.1.5" + date-fns "2.29.3" json-stable-stringify "^1.0.1" lodash "^4.17.13" microee "^0.0.6" @@ -5979,6 +5980,15 @@ cozy-stack-client@^33.0.0: mime "^2.4.0" qs "^6.7.0" +cozy-stack-client@^34.1.5: + version "34.1.5" + resolved "https://registry.yarnpkg.com/cozy-stack-client/-/cozy-stack-client-34.1.5.tgz#28fbc22b72f6343d968d4899d91c70f0261252f4" + integrity sha512-i0GsaaHNI2XmXUncbNPzuFY+DDC4/io3m7mwCmhAFyI/REHPdqOi3Oo5Mb7Euuky4A6iZjAWn5t0F69itv3rvg== + dependencies: + detect-node "^2.0.4" + mime "^2.4.0" + qs "^6.7.0" + create-ecdh@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" @@ -6450,6 +6460,11 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +date-fns@2.29.3: + version "2.29.3" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" + integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== + date-fns@^1.28.5, date-fns@^1.30.1: version "1.30.1" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" From 7705cae041bae0409e42cbf669c13988013da31c Mon Sep 17 00:00:00 2001 From: PolariTOON <36267812+PolariTOON@users.noreply.github.com> Date: Wed, 7 Dec 2022 15:47:26 +0100 Subject: [PATCH 2/7] feat: Add an `ExpirationAnnotation` component --- .../components/ExpirationAnnotation.jsx | 38 +++++++++++++++++++ react/Viewer/locales/en.json | 4 +- react/Viewer/locales/fr.json | 4 +- 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 react/Viewer/components/ExpirationAnnotation.jsx diff --git a/react/Viewer/components/ExpirationAnnotation.jsx b/react/Viewer/components/ExpirationAnnotation.jsx new file mode 100644 index 0000000000..3379d68650 --- /dev/null +++ b/react/Viewer/components/ExpirationAnnotation.jsx @@ -0,0 +1,38 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import { models } from 'cozy-client' + +import Typography from '../../Typography' +import { useI18n } from '../../I18n' +import { formatLocallyDistanceToNow } from '../../I18n/format' + +const { computeExpirationDate, isExpired } = models.paper + +const ExpirationAnnotation = ({ file }) => { + const { t } = useI18n() + + if (isExpired(file)) { + return ( + + {t('Viewer.panel.qualification.expired')} + + ) + } + + const expirationDate = computeExpirationDate(file) + + return ( + + {t('Viewer.panel.qualification.expiresIn', { + duration: formatLocallyDistanceToNow(expirationDate) + })} + + ) +} + +ExpirationAnnotation.propTypes = { + file: PropTypes.object.isRequired +} + +export default ExpirationAnnotation diff --git a/react/Viewer/locales/en.json b/react/Viewer/locales/en.json index 35fc3c54b1..de1e4e3988 100644 --- a/react/Viewer/locales/en.json +++ b/react/Viewer/locales/en.json @@ -72,7 +72,9 @@ "copy": "Copy", "copyClipboard": "Copy to clipboard", "edit": "Edit" - } + }, + "expired": "Expired", + "expiresIn": "Expires in %{duration}" }, "title": "Useful information" }, diff --git a/react/Viewer/locales/fr.json b/react/Viewer/locales/fr.json index 50455706e0..ab68a301c1 100644 --- a/react/Viewer/locales/fr.json +++ b/react/Viewer/locales/fr.json @@ -72,7 +72,9 @@ "copy": "Copier", "copyClipboard": "Copier dans le presse-papier", "edit": "Modifier" - } + }, + "expired": "Expiré", + "expiresIn": "Expire dans %{duration}" }, "title": "Informations utiles" }, From 763790dcfba862b88f1b320521b7562e63ae3972 Mon Sep 17 00:00:00 2001 From: PolariTOON <36267812+PolariTOON@users.noreply.github.com> Date: Wed, 7 Dec 2022 15:47:34 +0100 Subject: [PATCH 3/7] feat: Add expiration annotations to date qualifications --- .../Panel/QualificationListItemDate.jsx | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/react/Viewer/Panel/QualificationListItemDate.jsx b/react/Viewer/Panel/QualificationListItemDate.jsx index 107b0e1241..11c655a3ec 100644 --- a/react/Viewer/Panel/QualificationListItemDate.jsx +++ b/react/Viewer/Panel/QualificationListItemDate.jsx @@ -1,17 +1,23 @@ import React, { forwardRef } from 'react' import PropTypes from 'prop-types' +import { models } from 'cozy-client' + import ListItem from '../../MuiCozyTheme/ListItem' import ListItemSecondaryAction from '../../MuiCozyTheme/ListItemSecondaryAction' import IconButton from '../../IconButton' import Icon from '../../Icon' import Dots from '../../Icons/Dots' +import Typography from '../../Typography' +import ExpirationAnnotation from '../components/ExpirationAnnotation' import QualificationListItemText from './QualificationListItemText' import { useI18n } from '../../I18n' import { formatDate } from '../helpers' +const { isExpired, isExpiringSoon } = models.paper + const QualificationListItemDate = forwardRef( - ({ formatedMetadataQualification, toggleActionsMenu }, ref) => { + ({ file, formatedMetadataQualification, toggleActionsMenu }, ref) => { const { t, f, lang } = useI18n() const { name, value } = formatedMetadataQualification const formattedDate = value @@ -22,7 +28,21 @@ const QualificationListItemDate = forwardRef( + + {formattedDate} + + {(isExpired(file) || isExpiringSoon(file)) && ( + <> + + {' · '} + + + + )} + + } disabled={!value} /> @@ -41,6 +61,7 @@ const QualificationListItemDate = forwardRef( QualificationListItemDate.displayName = 'QualificationListItemDate' QualificationListItemDate.propTypes = { + file: PropTypes.object.isRequired, formatedMetadataQualification: PropTypes.shape({ name: PropTypes.string, value: PropTypes.string From 36d019d33655aa8ce2f81a2187b5e1d0f6ac0ef4 Mon Sep 17 00:00:00 2001 From: PolariTOON <36267812+PolariTOON@users.noreply.github.com> Date: Wed, 7 Dec 2022 17:34:16 +0100 Subject: [PATCH 4/7] feat: Add an `ExpirationAlert` component --- react/Viewer/components/ExpirationAlert.jsx | 81 +++++++++++++++++++++ react/Viewer/locales/en.json | 4 + react/Viewer/locales/fr.json | 4 + 3 files changed, 89 insertions(+) create mode 100644 react/Viewer/components/ExpirationAlert.jsx diff --git a/react/Viewer/components/ExpirationAlert.jsx b/react/Viewer/components/ExpirationAlert.jsx new file mode 100644 index 0000000000..21b8cc4842 --- /dev/null +++ b/react/Viewer/components/ExpirationAlert.jsx @@ -0,0 +1,81 @@ +import React, { useState } from 'react' +import PropTypes from 'prop-types' + +import { useClient, models } from 'cozy-client' + +import Alert from '../../Alert' +import Button from '../../Buttons' +import Link from '../../Link' +import Typography from '../../Typography' +import { withViewerLocales } from '../hoc/withViewerLocales' +import { useI18n } from '../../I18n' +import { formatLocallyDistanceToNow } from '../../I18n/format' + +const FILES_DOCTYPE = 'io.cozy.files' + +const { computeExpirationDate, computeExpirationNoticeLink } = models.paper + +const ExpirationAlert = ({ file }) => { + const { t } = useI18n() + const client = useClient() + const [isBusy, setIsBusy] = useState(false) + + const handleClose = async () => { + setIsBusy(true) + await client.collection(FILES_DOCTYPE).updateMetadataAttribute(file.id, { + ...file.metadata, + hideExpirationAlert: true + }) + setIsBusy(false) + } + + const expirationDate = computeExpirationDate(file) + const expirationNoticeLink = computeExpirationNoticeLink(file) + + return ( + + } + className="u-mt-1 u-mh-1" + > + + + {t('Viewer.panel.expiration.description', { + duration: formatLocallyDistanceToNow(expirationDate) + })} + + {expirationNoticeLink && ( + <> + + {' : '} + + + {new URL(expirationNoticeLink).hostname} + + + )} + + + ) +} + +ExpirationAlert.propTypes = { + file: PropTypes.object.isRequired +} + +export default withViewerLocales(ExpirationAlert) diff --git a/react/Viewer/locales/en.json b/react/Viewer/locales/en.json index de1e4e3988..7363e4682d 100644 --- a/react/Viewer/locales/en.json +++ b/react/Viewer/locales/en.json @@ -76,6 +76,10 @@ "expired": "Expired", "expiresIn": "Expires in %{duration}" }, + "expiration": { + "description": "This document will expire in %{duration}, consider renewing it", + "dismiss": "I understood" + }, "title": "Useful information" }, "previous": "Previous", diff --git a/react/Viewer/locales/fr.json b/react/Viewer/locales/fr.json index ab68a301c1..93349bee81 100644 --- a/react/Viewer/locales/fr.json +++ b/react/Viewer/locales/fr.json @@ -76,6 +76,10 @@ "expired": "Expiré", "expiresIn": "Expire dans %{duration}" }, + "expiration": { + "description": "Ce document expirera dans %{duration}, pensez à le renouveler", + "dismiss": "J'ai compris" + }, "title": "Informations utiles" }, "previous": "Précédente", From 2afb4457fb95c60807b24452b8a13483d3a04910 Mon Sep 17 00:00:00 2001 From: PolariTOON <36267812+PolariTOON@users.noreply.github.com> Date: Wed, 7 Dec 2022 15:49:34 +0100 Subject: [PATCH 5/7] feat: Add the expiration alert to the qualification block --- react/Viewer/Panel/Qualification.jsx | 56 ++++++++++++++++------------ 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/react/Viewer/Panel/Qualification.jsx b/react/Viewer/Panel/Qualification.jsx index d43b97561a..2eee3ec901 100644 --- a/react/Viewer/Panel/Qualification.jsx +++ b/react/Viewer/Panel/Qualification.jsx @@ -1,6 +1,8 @@ import React, { useRef, useState, createRef, useMemo, useEffect } from 'react' import PropTypes from 'prop-types' +import { models } from 'cozy-client' + import List from '../../MuiCozyTheme/List' import { withViewerLocales } from '../hoc/withViewerLocales' import { @@ -9,12 +11,15 @@ import { knownInformationMetadataNames, knownOtherMetadataNames } from '../helpers' +import ExpirationAlert from '../components/ExpirationAlert' import QualificationListItemContact from './QualificationListItemContact' import ActionMenuWrapper from './ActionMenuWrapper' import QualificationListItemDate from './QualificationListItemDate' import QualificationListItemInformation from './QualificationListItemInformation' import QualificationListItemOther from './QualificationListItemOther' +const { isExpiringSoon } = models.paper + const makeQualificationListItemComp = metadataName => { if (knownDateMetadataNames.includes(metadataName)) { return QualificationListItemDate @@ -63,31 +68,36 @@ const Qualification = ({ file = {} }) => { }, [formatedMetadataQualification]) return ( - - {formatedMetadataQualification.map((meta, idx) => { - const { name } = meta - const QualificationListItemComp = makeQualificationListItemComp(name) - - return ( - + {isExpiringSoon(file) && !file?.metadata?.hideExpirationAlert && ( + + )} + + {formatedMetadataQualification.map((meta, idx) => { + const { name } = meta + const QualificationListItemComp = makeQualificationListItemComp(name) + + return ( + toggleActionsMenu(idx, name, val)} + /> + ) + })} + + {optionFile.name && ( + toggleActionsMenu(idx, name, val)} + optionFile={optionFile} + ref={actionBtnRef.current[optionFile.id]} /> - ) - })} - - {optionFile.name && ( - - )} - + )} + + ) } From 27fff188a767ce93e6c15420150d0eaa30517f58 Mon Sep 17 00:00:00 2001 From: PolariTOON <36267812+PolariTOON@users.noreply.github.com> Date: Wed, 7 Dec 2022 17:32:48 +0100 Subject: [PATCH 6/7] fix: Require `file` prop in `Qualification` --- react/Viewer/Panel/Qualification.jsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/react/Viewer/Panel/Qualification.jsx b/react/Viewer/Panel/Qualification.jsx index 2eee3ec901..ee59bfbce2 100644 --- a/react/Viewer/Panel/Qualification.jsx +++ b/react/Viewer/Panel/Qualification.jsx @@ -37,7 +37,11 @@ const makeQualificationListItemComp = metadataName => { } } -const Qualification = ({ file = {} }) => { +const isExpirationAlertHidden = file => { + return file?.metadata?.hideExpirationAlert ?? false +} + +const Qualification = ({ file }) => { const { metadata = {} } = file const actionBtnRef = useRef([]) const [optionFile, setOptionFile] = useState({ @@ -69,7 +73,7 @@ const Qualification = ({ file = {} }) => { return ( <> - {isExpiringSoon(file) && !file?.metadata?.hideExpirationAlert && ( + {isExpiringSoon(file) && !isExpirationAlertHidden(file) && ( )} @@ -102,7 +106,7 @@ const Qualification = ({ file = {} }) => { } Qualification.propTypes = { - file: PropTypes.object + file: PropTypes.object.isRequired } export default withViewerLocales(Qualification) From a12d0d852786e6d61c57184f5555c7360df06151 Mon Sep 17 00:00:00 2001 From: PolariTOON <36267812+PolariTOON@users.noreply.github.com> Date: Wed, 30 Nov 2022 12:36:35 +0100 Subject: [PATCH 7/7] docs: Add an example of a file with many panel blocks in the viewer Including an expiration alert. --- react/Viewer/Readme.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/react/Viewer/Readme.md b/react/Viewer/Readme.md index 591a3b8a07..a19db18c02 100644 --- a/react/Viewer/Readme.md +++ b/react/Viewer/Readme.md @@ -122,7 +122,16 @@ const files = [ _id: 'image', class: 'image', name: 'Demo.jpg', - mime: 'image/jpg' + mime: 'image/jpg', + metadata: { + carbonCopy: true, + electronicSafe: true, + referencedDate: new Date(Date.now() - 357 * 24 * 60 * 60 * 1000).toISOString(), + datetimeLabel: "referencedDate", + qualification: { + label: 'personal_sporting_licence' + } + } }, { _id: 'none',