diff --git a/cypress/e2e/item/share/shareItem.cy.ts b/cypress/e2e/item/share/shareItem.cy.ts index 40f3ea607..fc65060a3 100644 --- a/cypress/e2e/item/share/shareItem.cy.ts +++ b/cypress/e2e/item/share/shareItem.cy.ts @@ -9,6 +9,8 @@ import { SHARE_ITEM_DIALOG_LINK_ID, SHARE_ITEM_DIALOG_LINK_SELECT_ID, SHARE_ITEM_PSEUDONYMIZED_SCHEMA_ID, + SHARE_ITEM_QR_BTN_ID, + SHARE_ITEM_QR_DIALOG_ID, SHARE_ITEM_VISIBILITY_SELECT_ID, buildShareButtonId, } from '../../../../src/config/selectors'; @@ -129,4 +131,15 @@ describe('Share Item', () => { expect(url).to.include(item.id); }); }); + + it('Share Item with QR Code', () => { + cy.setUpApi({ ...SAMPLE_PUBLIC_ITEMS }); + const item = SAMPLE_PUBLIC_ITEMS.items[0]; + cy.visit(buildItemPath(item.id)); + openShareItemTab(item.id); + + cy.get(`#${SHARE_ITEM_QR_BTN_ID}`).click(); + + cy.get(`#${SHARE_ITEM_QR_DIALOG_ID}`).should('exist'); + }); }); diff --git a/package.json b/package.json index 54d2a3271..ae5e5b2f8 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "react-ga4": "2.1.0", "react-i18next": "13.2.0", "react-image-crop": "9.1.1", + "react-qr-code": "2.0.12", "react-query": "3.39.3", "react-quill": "2.0.0", "react-router": "6.15.0", diff --git a/src/components/common/QRCode.tsx b/src/components/common/QRCode.tsx new file mode 100644 index 000000000..698fc3865 --- /dev/null +++ b/src/components/common/QRCode.tsx @@ -0,0 +1,62 @@ +import { useState } from 'react'; +import QR from 'react-qr-code'; + +import { QrCode2 } from '@mui/icons-material'; +import CloseIcon from '@mui/icons-material/Close'; +import { Box, Dialog, DialogContent, IconButton, Tooltip } from '@mui/material'; + +import { useBuilderTranslation } from '@/config/i18n'; +import { + SHARE_ITEM_QR_BTN_ID, + SHARE_ITEM_QR_DIALOG_ID, +} from '@/config/selectors'; +import { BUILDER } from '@/langs/constants'; + +type Props = { + value: string; +}; + +const QRCode = ({ value }: Props): JSX.Element => { + const { t: translateBuilder } = useBuilderTranslation(); + const [openQrModal, setOpenQrModal] = useState(false); + + return ( + <> + + setOpenQrModal(true)} + id={SHARE_ITEM_QR_BTN_ID} + > + + + + setOpenQrModal(false)} + id={SHARE_ITEM_QR_DIALOG_ID} + > + setOpenQrModal(false)} + sx={{ + position: 'absolute', + right: 8, + top: 8, + }} + > + + + + + + + + + + ); +}; + +export default QRCode; diff --git a/src/components/item/sharing/SharingLink.tsx b/src/components/item/sharing/SharingLink.tsx index 1a168d60e..a0956aa8b 100644 --- a/src/components/item/sharing/SharingLink.tsx +++ b/src/components/item/sharing/SharingLink.tsx @@ -13,6 +13,7 @@ import { FAILURE_MESSAGES, SUCCESS_MESSAGES } from '@graasp/translations'; import shortUUID from 'short-uuid'; +import QRCode from '@/components/common/QRCode'; import { SHARE_LINK_COLOR, SHARE_LINK_CONTAINER_BORDER_STYLE, @@ -156,6 +157,7 @@ const SharingLink = ({ itemId }: Props): JSX.Element => { + {link && } ); diff --git a/src/config/selectors.ts b/src/config/selectors.ts index 5a3bce92a..ea9f5a675 100644 --- a/src/config/selectors.ts +++ b/src/config/selectors.ts @@ -168,6 +168,8 @@ export const INVITE_ITEM_BUTTON_ID = 'inviteItemButton'; export const SHARE_ITEM_DIALOG_ID = 'shareItemDialog'; export const SHARE_ITEM_DIALOG_LINK_ID = 'shareItemDialogLink'; export const SHARE_ITEM_DIALOG_LINK_SELECT_ID = 'shareItemDialogLinkSelect'; +export const SHARE_ITEM_QR_BTN_ID = 'shareItemQRBtn'; +export const SHARE_ITEM_QR_DIALOG_ID = 'shareItemQRDialog'; export const ACCESS_INDICATION_ID = 'accessIndication'; export const ITEM_CHATBOX_BUTTON_ID = 'itemChatboxButton'; export const CHATBOX_ID = 'chatbox'; diff --git a/src/langs/ar.json b/src/langs/ar.json index 9bc8ed6d5..e1189a164 100644 --- a/src/langs/ar.json +++ b/src/langs/ar.json @@ -211,6 +211,7 @@ "SHARE_ITEM_FORM_INVITATION_INVALID_EMAIL_MESSAGE": "هذا البريد غير صالح", "SHARE_ITEM_FORM_INVITATION_TOOLTIP": "سيتلقى المستخدمون الغير مسجّلين رابطًا شخصيًا للتسجيل في المنصة.", "SHARE_ITEM_LINK_COPY_TOOLTIP": "النّسخ إلى الحافظة", + "SHARE_ITEM_LINK_QR_CODE": "أنشئ رمز الاستجابة", "SHARED_ITEMS_TITLE": "العناصر المنشورة", "SHARED_MEMBERS_LABEL": "الأعضاء المنشورين", "SHARED_MEMBERS_TOOLTIP_one": "تمّت مشاركة هذا العنصر مع مستخدم واحد", diff --git a/src/langs/constants.ts b/src/langs/constants.ts index 226584d55..4118097be 100644 --- a/src/langs/constants.ts +++ b/src/langs/constants.ts @@ -270,6 +270,7 @@ export const BUILDER = { SETTINGS_THUMBNAIL_TITLE: 'SETTINGS_THUMBNAIL_TITLE', SHARE_ITEM_CSV_IMPORT_BUTTON: 'SHARE_ITEM_CSV_IMPORT_BUTTON', SHARE_ITEM_LINK_COPY_TOOLTIP: 'SHARE_ITEM_LINK_COPY_TOOLTIP', + SHARE_ITEM_LINK_QR_CODE: 'SHARE_ITEM_LINK_QR_CODE', SHARED_ITEMS_TITLE: 'SHARED_ITEMS_TITLE', SHARED_MEMBERS_LABEL: 'SHARED_MEMBERS_LABEL', SHARED_MEMBERS_TOOLTIP: 'SHARED_MEMBERS_TOOLTIP', diff --git a/src/langs/en.json b/src/langs/en.json index 56303fdf7..9a9379695 100644 --- a/src/langs/en.json +++ b/src/langs/en.json @@ -211,6 +211,7 @@ "SHARE_ITEM_FORM_INVITATION_INVALID_EMAIL_MESSAGE": "This mail is not valid", "SHARE_ITEM_FORM_INVITATION_TOOLTIP": "Non-registered users will receive a personal link to register on the platform.", "SHARE_ITEM_LINK_COPY_TOOLTIP": "Copy to Clipboard", + "SHARE_ITEM_LINK_QR_CODE": "Generate QR Code", "SHARED_ITEMS_TITLE": "Shared Items", "SHARED_MEMBERS_LABEL": "Shared Members", "SHARED_MEMBERS_TOOLTIP_one": "This item is shared with one user", diff --git a/yarn.lock b/yarn.lock index eb42ca3dd..b4d69b6dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7501,6 +7501,7 @@ __metadata: react-ga4: 2.1.0 react-i18next: 13.2.0 react-image-crop: 9.1.1 + react-qr-code: 2.0.12 react-query: 3.39.3 react-quill: 2.0.0 react-router: 6.15.0 @@ -10766,6 +10767,13 @@ __metadata: languageName: node linkType: hard +"qr.js@npm:0.0.0": + version: 0.0.0 + resolution: "qr.js@npm:0.0.0" + checksum: 5ac6c393967bdeaa660e7fd3a501a25eb538c1f6008a4d30ab2b97bbe520e5c236530090773f1578aa0a523cdaa6923c866615e21143f9e7cd22abd41c789b69 + languageName: node + linkType: hard + "qs@npm:6.10.4": version: 6.10.4 resolution: "qs@npm:6.10.4" @@ -11034,6 +11042,22 @@ __metadata: languageName: node linkType: hard +"react-qr-code@npm:2.0.12": + version: 2.0.12 + resolution: "react-qr-code@npm:2.0.12" + dependencies: + prop-types: ^15.8.1 + qr.js: 0.0.0 + peerDependencies: + react: ^16.x || ^17.x || ^18.x + react-native-svg: "*" + peerDependenciesMeta: + react-native-svg: + optional: true + checksum: b7bad40d7d5f04f7ff336ae499920dd5ea0e7616ed7fec5f849e54f8f26b5e4acd1ba8e69198be8617dc7fecdf36cf4302c99ff74885320b55bb95d19a09de7c + languageName: node + linkType: hard + "react-query@npm:3.39.3": version: 3.39.3 resolution: "react-query@npm:3.39.3"