diff --git a/package-lock.json b/package-lock.json index 6b99cfc03..f831c763b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pass", - "version": "1.0.0-alpha", + "version": "1.1.0-alpha", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "pass", - "version": "1.0.0-alpha", + "version": "1.1.0-alpha", "license": "MIT", "dependencies": { "@emotion/react": "^11.10.8", @@ -5329,11 +5329,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, - "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -6404,9 +6405,9 @@ "dev": true }, "node_modules/ejs": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, "dependencies": { "jake": "^10.8.5" @@ -8376,9 +8377,10 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, - "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -9478,8 +9480,9 @@ }, "node_modules/is-number": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -9883,9 +9886,10 @@ } }, "node_modules/jose": { - "version": "4.15.4", + "version": "4.15.9", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", + "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" } @@ -11386,9 +11390,9 @@ "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "dev": true }, "node_modules/path-type": { @@ -13397,8 +13401,9 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -13799,9 +13804,9 @@ } }, "node_modules/vite": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", - "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.5.tgz", + "integrity": "sha512-ifW3Lb2sMdX+WU91s3R0FyQlAyLxOzCSCP37ujw0+r5POeHPwe6udWVIElKQq8gk3t7b8rkmvqC6IHBpCff4GQ==", "dev": true, "dependencies": { "esbuild": "^0.18.10", @@ -14293,9 +14298,10 @@ } }, "node_modules/ws": { - "version": "8.14.2", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, - "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -18495,10 +18501,12 @@ } }, "braces": { - "version": "3.0.2", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "browserslist": { @@ -19177,9 +19185,9 @@ "dev": true }, "ejs": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, "requires": { "jake": "^10.8.5" @@ -20503,7 +20511,9 @@ } }, "fill-range": { - "version": "7.0.1", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -21173,6 +21183,8 @@ }, "is-number": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "is-number-object": { @@ -21428,7 +21440,9 @@ } }, "jose": { - "version": "4.15.4", + "version": "4.15.9", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", + "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", "dev": true }, "js-tokens": { @@ -22397,9 +22411,9 @@ "version": "1.0.7" }, "path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "dev": true }, "path-type": { @@ -23720,6 +23734,8 @@ }, "to-regex-range": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -23978,9 +23994,9 @@ "dev": true }, "vite": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", - "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.5.tgz", + "integrity": "sha512-ifW3Lb2sMdX+WU91s3R0FyQlAyLxOzCSCP37ujw0+r5POeHPwe6udWVIElKQq8gk3t7b8rkmvqC6IHBpCff4GQ==", "dev": true, "requires": { "esbuild": "^0.18.10", @@ -24255,7 +24271,9 @@ } }, "ws": { - "version": "8.14.2", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index 6022d39bb..33e43f373 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pass", "homepage": ".", - "version": "1.0.0-alpha", + "version": "1.1.0-alpha", "description": "", "scripts": { "start": "concurrently --kill-others \"npm run podserver\" \"npm run dev\"", diff --git a/src/AppRoutes.jsx b/src/AppRoutes.jsx index 3877fba42..3de9ec87a 100644 --- a/src/AppRoutes.jsx +++ b/src/AppRoutes.jsx @@ -7,7 +7,7 @@ import { useSession } from '@hooks'; import { CIVIC_FORM_LIST, FormLayout } from '@components/CivicProfileForms'; import { MESSAGE_PAGES_LIST, MessagesLayout } from '@components/Messages'; // Page Imports -import { CivicProfile, Home, Contacts, Profile, Signup } from './pages'; +import { CivicProfile, Documents, Home, Contacts, Profile, Signup } from './pages'; const ProtectedRoute = ({ isLoggedIn, children }) => isLoggedIn ? children ?? : ; @@ -58,6 +58,7 @@ const AppRoutes = () => { ))} } /> + } /> {/* TODO: Remove blank Civic Profile page, ensure it directs Basic Information instead */} }> {CIVIC_FORM_LIST.map((formProps) => ( diff --git a/src/components/Contacts/ContactListTable.jsx b/src/components/Contacts/ContactListTable.jsx index a1c035418..dbe234acb 100644 --- a/src/components/Contacts/ContactListTable.jsx +++ b/src/components/Contacts/ContactListTable.jsx @@ -26,15 +26,16 @@ import ContactListTableMobile from './ContactListTableMobile'; * @param {Function} Props.addContact - from Contacts page * @returns {React.JSX.Element} The ContactListTable Component */ -const ContactListTable = ({ contacts, deleteContact, handleDeleteContact, addContact }) => { +const ContactListTable = ({ contacts = [], deleteContact, handleDeleteContact, addContact }) => { const [showMessageModal, setShowMessageModal] = useState(false); const [messageToField, setMessageToField] = useState(''); - const theme = useTheme(); - const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); - const [showAddContactModal, setShowAddContactModal] = useState(false); - const [contactToEdit, setContactToEdit] = useState({}); + const [contactToEdit, setContactToEdit] = useState(null); const [isEditing, setIsEditing] = useState(false); + const contactWebIds = contacts.map(({ webId }) => webId); + const theme = useTheme(); + const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); + const isSmallScreenHeight = useMediaQuery('(max-height: 600px)'); const handleSendMessage = (contactId) => { setShowMessageModal(!showMessageModal); @@ -47,17 +48,15 @@ const ContactListTable = ({ contacts, deleteContact, handleDeleteContact, addCon setIsEditing(true); }; - const contactWebIds = contacts.map(({ webId }) => webId); - return ( - {isSmallScreen ? ( + {isSmallScreen || isSmallScreenHeight ? ( ); diff --git a/src/components/Contacts/ContactListTableDesktop.jsx b/src/components/Contacts/ContactListTableDesktop.jsx index 8cac2d9bd..f4dfdef84 100644 --- a/src/components/Contacts/ContactListTableDesktop.jsx +++ b/src/components/Contacts/ContactListTableDesktop.jsx @@ -40,7 +40,6 @@ const CustomToolbar = () => ( * @param {Function} Props.editContact - Function to edit a contact * @param {Function} Props.handleSendMessage - Function to handle sending a message * @param {string} Props.'data-testid' - Test ID -// * @param {Function} Props.handleProfileClick - Function to handle profile click * @returns {React.JSX.Element} The ContactListTableDesktop component */ const ContactListTableDesktop = ({ diff --git a/src/components/Documents/DocumentCard.jsx b/src/components/Documents/DocumentCard.jsx index af2b6a474..72de71b8d 100644 --- a/src/components/Documents/DocumentCard.jsx +++ b/src/components/Documents/DocumentCard.jsx @@ -1,5 +1,6 @@ // React Imports import React, { useState } from 'react'; +import { useLocation } from 'react-router-dom'; // Material UI Imports import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; @@ -41,6 +42,9 @@ import { truncateText, getTypeText } from '@utils'; * @returns {React.JSX.Element} The DocumentCard component */ const DocumentCard = ({ document, onShare, onDelete, onPreview }) => { + const location = useLocation(); + const profileWebId = decodeURIComponent(location.pathname.split('/')[2]); + const [anchorEl, setAnchorEl] = useState(null); const [openMenu, setOpenMenu] = useState(null); @@ -149,22 +153,26 @@ const DocumentCard = ({ document, onShare, onDelete, onPreview }) => { > Preview - } - sx={iconStyling} - > - Share - - } - sx={iconStyling} - > - Delete - + {`${profileWebId}` === 'undefined' && ( + } + sx={iconStyling} + > + Share + + )} + {`${profileWebId}` === 'undefined' && ( + } + sx={iconStyling} + > + Delete + + )} diff --git a/src/components/Documents/DocumentTable.jsx b/src/components/Documents/DocumentTable.jsx index 658db4254..01c01adc7 100644 --- a/src/components/Documents/DocumentTable.jsx +++ b/src/components/Documents/DocumentTable.jsx @@ -37,6 +37,7 @@ const DocumentTable = ({ handleAclPermissionsModal, handleSelectDeleteDoc }) => const { documentListObject, loadingDocuments } = useContext(DocumentListContext); const isMobile = useMediaQuery(theme.breakpoints.down('sm')); + const isSmallScreenHeight = useMediaQuery('(max-height: 600px)'); /** * Handles the local display of a document by opening it in a new window. @@ -98,7 +99,7 @@ const DocumentTable = ({ handleAclPermissionsModal, handleSelectDeleteDoc }) => }} data-testid="document-table" > - {isMobile ? ( + {isMobile || isSmallScreenHeight ? ( ) : ( ( * @returns {React.JSX.Element} The DocumentsDesktop component */ const DocumentsDesktop = ({ documents, handlers }) => { + const { session } = useSession(); + const location = useLocation(); + const profileWebId = decodeURIComponent(location.pathname.split('/')[2]); + const columnTitlesArray = [ { field: 'Name', minWidth: 120, flex: 1, headerAlign: 'center', align: 'center' }, { field: 'Type', minWidth: 120, flex: 1, headerAlign: 'center', align: 'center' }, @@ -109,6 +116,7 @@ const DocumentsDesktop = ({ documents, handlers }) => { onClick={() => handlers.onShare('document', name, type)} label="Share" data-testid={`share-button-${id}`} + disabled={session.info.webId !== profileWebId} /> ); } @@ -130,6 +138,7 @@ const DocumentsDesktop = ({ documents, handlers }) => { onClick={() => handlers.onDelete(document)} label="Delete" data-testid={`delete-button-${document.id}`} + disabled={session.info.webId !== profileWebId} /> ); } diff --git a/src/components/Footer/Footer.jsx b/src/components/Footer/Footer.jsx index 7d6f69576..52823bbb6 100644 --- a/src/components/Footer/Footer.jsx +++ b/src/components/Footer/Footer.jsx @@ -21,6 +21,7 @@ import RenderCopyrightAndLinksSection from './RenderCopyrightAndLinksSection'; const Footer = () => { const theme = useTheme(); const isReallySmallScreen = useMediaQuery(theme.breakpoints.down('sm')); + const isSmallScreenHeight = useMediaQuery('(max-height: 600px)'); return ( { > } > diff --git a/src/components/Modals/AddContactModal.jsx b/src/components/Modals/AddContactModal.jsx index e61062924..f940e67cb 100644 --- a/src/components/Modals/AddContactModal.jsx +++ b/src/components/Modals/AddContactModal.jsx @@ -129,8 +129,8 @@ const AddContactModal = ({ useEffect(() => { // sets fields if form is set to Edit if (isEditing) { - setUserGivenName(contactToEdit?.givenName); - setUserFamilyName(contactToEdit?.familyName); + setUserGivenName(contactToEdit?.givenName ?? ''); + setUserFamilyName(contactToEdit?.familyName ?? ''); // parse out webid and usernames and set them to the state values parsePodUrl(); diff --git a/src/components/Modals/NewMessageModal.jsx b/src/components/Modals/NewMessageModal.jsx index d461762c7..efd1df100 100644 --- a/src/components/Modals/NewMessageModal.jsx +++ b/src/components/Modals/NewMessageModal.jsx @@ -59,10 +59,19 @@ const NewMessageModal = ({ showModal, setShowModal, oldMessage = '', toField = ' const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); const contactListOptions = - data?.map((contact) => ({ - label: `${contact.person} ${contact.podUrl}`, - id: contact.podUrl - })) ?? []; + data?.map((contact) => { + let contactName; + if (contact.givenName !== '' || contact.givenName !== null) { + contactName = contact.givenName; + } + if (contact.familyName !== '' || contact.familyName !== null) { + contactName += ` ${contact.familyName}`.trim(); + } + return { + label: `${contactName} ${contact.podUrl}`.trim(), + id: contact.podUrl + }; + }) ?? []; const recipientName = data?.filter((contact) => message.recipientPodUrl === contact.podUrl)[0]; // Modifies message upon input const handleChange = (e) => { @@ -137,7 +146,7 @@ const NewMessageModal = ({ showModal, setShowModal, oldMessage = '', toField = ' data-testid="newMessageTo" id="recipientPodUrl" freeSolo - value={recipientName?.person ?? message.recipientPodUrl} + value={recipientName?.podUrl ?? message.recipientPodUrl} disablePortal autoSelect options={contactListOptions} diff --git a/src/components/Modals/WebcamModal.jsx b/src/components/Modals/WebcamModal.jsx index 97f8e84ff..78805bf5b 100644 --- a/src/components/Modals/WebcamModal.jsx +++ b/src/components/Modals/WebcamModal.jsx @@ -1,14 +1,24 @@ // React Imports -import React, { useRef } from 'react'; +import React, { useRef, useState } from 'react'; import Webcam from 'react-webcam'; // Material UI Imports import Button from '@mui/material/Button'; import Modal from '@mui/material/Modal'; +import CameraswitchIcon from '@mui/icons-material/Cameraswitch'; // TODO: Determine future of this modal // web camera modal const WebcamModal = ({ open, onClose, onCapture }) => { const webcamRef = useRef(null); + const [facingDirection, setFacingDirection] = useState('environment'); + + const handleCameraDirection = () => { + if (facingDirection === 'environment') { + setFacingDirection('user'); + } else { + setFacingDirection('environment'); + } + }; const handleCapture = () => { const imageSrc = webcamRef.current.getScreenshot(); @@ -29,19 +39,27 @@ const WebcamModal = ({ open, onClose, onCapture }) => { flexDirection: 'column', alignItems: 'center', justifyContent: 'center', - height: '100vh' + gap: '10px', + height: '100dvh' }} > -

Webcam

- +
+ + + +
); diff --git a/src/components/NavBar/NavMenu.jsx b/src/components/NavBar/NavMenu.jsx index ecba8d2d9..1bc943747 100644 --- a/src/components/NavBar/NavMenu.jsx +++ b/src/components/NavBar/NavMenu.jsx @@ -10,6 +10,7 @@ import ContactsIcon from '@mui/icons-material/Contacts'; import Divider from '@mui/material/Divider'; import Drawer from '@mui/material/Drawer'; import EmailIcon from '@mui/icons-material/Email'; +import InventoryIcon from '@mui/icons-material/Inventory'; import LogoutIcon from '@mui/icons-material/Logout'; import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; @@ -139,6 +140,18 @@ const NavMenu = ({ Civic Profile + + } + sx={iconStyling} + > + Documents + + )} diff --git a/src/components/NavBar/NavbarLinks.jsx b/src/components/NavBar/NavbarLinks.jsx index 74c056a11..668da1901 100644 --- a/src/components/NavBar/NavbarLinks.jsx +++ b/src/components/NavBar/NavbarLinks.jsx @@ -23,7 +23,8 @@ const NavbarLinks = () => { // Array of current nav links for menus const routesArray = [ { label: 'Contacts', path: '/contacts' }, - { label: 'Civic Profile', path: '/civic-profile/basic-info' } + { label: 'Civic Profile', path: '/civic-profile/basic-info' }, + { label: 'Documents', path: '/documents' } ]; return ( diff --git a/src/hooks/useContactsList.js b/src/hooks/useContactsList.js index e9a1925ab..30d020693 100644 --- a/src/hooks/useContactsList.js +++ b/src/hooks/useContactsList.js @@ -50,16 +50,11 @@ const useContactsList = () => { }; const serialize = ({ givenName, familyName, webId }) => { - let builder = buildThing(createThing({ name: encodeURIComponent(webId) })) + const builder = buildThing(createThing({ name: encodeURIComponent(webId) })) .addUrl(RDF_PREDICATES.identifier, webId) - .addUrl(RDF_PREDICATES.URL, webId.split('profile')[0]); - - if (givenName) { - builder = builder.addStringNoLocale(RDF_PREDICATES.givenName, givenName); - } - if (familyName) { - builder = builder.addStringNoLocale(RDF_PREDICATES.familyName, familyName); - } + .addUrl(RDF_PREDICATES.URL, webId.split('profile')[0]) + .addStringNoLocale(RDF_PREDICATES.givenName, givenName ?? '') + .addStringNoLocale(RDF_PREDICATES.familyName, familyName ?? ''); return builder.build(); }; diff --git a/src/hooks/useTableSort.js b/src/hooks/useTableSort.js index 6b9258ffd..158a08448 100644 --- a/src/hooks/useTableSort.js +++ b/src/hooks/useTableSort.js @@ -1,22 +1,36 @@ -// hooks/useSortedData.js -import { useState, useEffect } from 'react'; +import { useEffect, useState } from 'react'; -const useSortedData = (initialData, getFieldValue, initialFieldType) => { - const [fieldType, setFieldType] = useState(initialFieldType); +const useTableSort = (initialData, initialSortValue) => { const [sortedData, setSortedData] = useState([]); + const [sortValue, setSortValue] = useState(initialSortValue); + + const sortData = (value) => { + const sorted = [...initialData].sort((a, b) => { + if (value === 'First Name') { + return a.givenName.localeCompare(b.givenName); + } + if (value === 'Last Name') { + return a.familyName.localeCompare(b.familyName); + } + if (value === 'Web ID') { + return a.webId.localeCompare(b.webId); + } + return 0; + }); + setSortedData(sorted); + }; useEffect(() => { - const sortData = (dataToSort, field) => - [...dataToSort].sort((a, b) => { - const fieldA = getFieldValue(a, field); - const fieldB = getFieldValue(b, field); - return fieldA.localeCompare(fieldB); - }); + setSortedData([...initialData]); + }, [initialData]); - setSortedData(sortData(initialData, fieldType)); - }, [fieldType, initialData, getFieldValue]); + useEffect(() => { + if (initialData.length > 0) { + sortData(sortValue, initialData); + } + }, [sortValue, initialData]); - return { fieldType, setFieldType, sortedData }; + return { sortedData, sortValue, setSortValue }; }; -export default useSortedData; +export default useTableSort; diff --git a/src/layouts/Breadcrumbs.jsx b/src/layouts/Breadcrumbs.jsx index 853196c46..95fea1b8f 100644 --- a/src/layouts/Breadcrumbs.jsx +++ b/src/layouts/Breadcrumbs.jsx @@ -36,7 +36,11 @@ const Breadcrumbs = () => { } - sx={{ margin: { xs: '20px', sm: '20px 80px' } }} + sx={{ + margin: { xs: '20px', sm: '20px 80px' }, + wordWrap: 'break-word', + overflowWrap: 'break-word' + }} > {crumbs.map((crumb, index) => index !== crumbs.length - 1 ? ( @@ -47,11 +51,20 @@ const Breadcrumbs = () => { .replaceAll(' ', '-') .toLowerCase()}`} key={crumb} + style={{ + wordBreak: 'break-word' + }} > {crumb} ) : ( - + {crumb} ) diff --git a/src/layouts/Layout.jsx b/src/layouts/Layout.jsx index b4775152e..9cf70b3a8 100644 --- a/src/layouts/Layout.jsx +++ b/src/layouts/Layout.jsx @@ -1,5 +1,6 @@ // React Imports import React from 'react'; +import { useLocation } from 'react-router-dom'; // Inrupt Library Imports import { useSession, useNotification } from '@hooks'; // Material UI Imports @@ -14,6 +15,7 @@ import Main from './Main'; const Layout = ({ ariaLabel, children }) => { const { session } = useSession(); const { state } = useNotification(); + const location = useLocation(); return ( { > - {session.info.isLoggedIn && } + {session.info.isLoggedIn && location.pathname !== '/profile' && }
{children}
{session.info.isLoggedIn && }