From b76a9e717cd072b9bbdd9fdb1f907fb0a63011c3 Mon Sep 17 00:00:00 2001 From: Ka Hung Lee Date: Thu, 19 Sep 2024 03:57:01 -0700 Subject: [PATCH 01/15] Update version to 1.0.1 for hotfix; Adjusted contact state for contact given and family names in contacts and new messages modal; Modified serialize functionality for contacts list to accept empty string as input; Force refetching of contacts list when reentering Contacts page --- package-lock.json | 90 +++++++++++-------- package.json | 2 +- src/components/Contacts/ContactListTable.jsx | 3 +- .../Contacts/ContactListTableDesktop.jsx | 1 - src/components/Modals/AddContactModal.jsx | 4 +- src/components/Modals/NewMessageModal.jsx | 19 ++-- src/hooks/useContactsList.js | 13 +-- src/pages/Contacts.jsx | 7 +- 8 files changed, 83 insertions(+), 56 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6b99cfc03..526eef920 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pass", - "version": "1.0.0-alpha", + "version": "1.0.1-alpha", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "pass", - "version": "1.0.0-alpha", + "version": "1.0.1-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..9101e60ca 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pass", "homepage": ".", - "version": "1.0.0-alpha", + "version": "1.0.1-alpha", "description": "", "scripts": { "start": "concurrently --kill-others \"npm run podserver\" \"npm run dev\"", diff --git a/src/components/Contacts/ContactListTable.jsx b/src/components/Contacts/ContactListTable.jsx index a1c035418..33f328062 100644 --- a/src/components/Contacts/ContactListTable.jsx +++ b/src/components/Contacts/ContactListTable.jsx @@ -33,7 +33,7 @@ const ContactListTable = ({ contacts, deleteContact, handleDeleteContact, addCon 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 handleSendMessage = (contactId) => { @@ -89,6 +89,7 @@ const ContactListTable = ({ contacts, deleteContact, handleDeleteContact, addCon handleDeleteContact={handleDeleteContact} contactWebIds={contactWebIds} contacts={contacts} + setContactToEdit={setContactToEdit} /> ); 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/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/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/pages/Contacts.jsx b/src/pages/Contacts.jsx index c8c67bf9e..3560a6394 100644 --- a/src/pages/Contacts.jsx +++ b/src/pages/Contacts.jsx @@ -1,5 +1,5 @@ // React Imports -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; // Material UI Imports import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; @@ -42,12 +42,17 @@ const Contacts = () => { isLoading, isError, error, + refetch, add: addContact, delete: deleteContact } = useContactsList(); const { addNotification } = useNotification(); const [fieldType, setFieldType] = useState('First Name'); + useEffect(() => { + refetch(); + }, []); + const getContactDisplayName = (contact) => { if (!contact) { return 'Unknown Contact'; From 9cc603dd6fd546ea215457fa69c5f724866deeec Mon Sep 17 00:00:00 2001 From: Ka Hung Lee Date: Thu, 19 Sep 2024 04:29:59 -0700 Subject: [PATCH 02/15] Updating unit tests to match with hotfixes --- test/components/Modals/NewMessageModal.test.jsx | 3 +-- test/pages/Contacts.test.jsx | 12 ++++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/test/components/Modals/NewMessageModal.test.jsx b/test/components/Modals/NewMessageModal.test.jsx index f6108282c..7210aaffd 100644 --- a/test/components/Modals/NewMessageModal.test.jsx +++ b/test/components/Modals/NewMessageModal.test.jsx @@ -113,7 +113,6 @@ it('selecting contact from autocomplete', async () => { { familyName: 'test', givenName: 'mock', - person: 'mock test', podUrl: 'http://example/mocktest', thingId: 'http://example/mocktest/profile/card#me', webId: 'http://example/mocktest/profile/card#me' @@ -135,5 +134,5 @@ it('selecting contact from autocomplete', async () => { // Enter to select dropdown option await userEvent.keyboard('[Enter]'); // verify value of input field - expect(toInput.value).toBe('mock test'); + expect(toInput.value).toBe('http://example/mocktest'); }); diff --git a/test/pages/Contacts.test.jsx b/test/pages/Contacts.test.jsx index eeefcf308..7430ee27e 100644 --- a/test/pages/Contacts.test.jsx +++ b/test/pages/Contacts.test.jsx @@ -23,7 +23,7 @@ describe('Contacts Page', () => { }); it('displays Loading message while loading', () => { - useContactsList.mockReturnValue({ isLoading: true }); + useContactsList.mockReturnValue({ isLoading: true, refetch: vi.fn() }); const { getByRole } = render( @@ -35,7 +35,11 @@ describe('Contacts Page', () => { it('displays Errors when fetch errors', () => { const errorMessage = 'error'; - useContactsList.mockReturnValue({ isError: true, error: { message: errorMessage } }); + useContactsList.mockReturnValue({ + isError: true, + error: { message: errorMessage }, + refetch: vi.fn() + }); const { getByText } = render( @@ -58,7 +62,7 @@ describe('Contacts Page', () => { givenName: 'Batman', webId: 'http://batman.com' }; - useContactsList.mockReturnValue({ data: [firstContact, secondContact] }); + useContactsList.mockReturnValue({ data: [firstContact, secondContact], refetch: vi.fn() }); const { getByRole } = render( @@ -70,7 +74,7 @@ describe('Contacts Page', () => { expect(contacts).not.toBeNull(); }); it('displays empty list message when there are no contacts', () => { - useContactsList.mockReturnValue({ data: [] }); + useContactsList.mockReturnValue({ data: [], refetch: vi.fn() }); const { getByLabelText } = render( From ed21cd499cbb8925d33aad250871029294c7cd0e Mon Sep 17 00:00:00 2001 From: jared krajewski Date: Thu, 19 Sep 2024 18:16:00 -0700 Subject: [PATCH 03/15] added vercel.json with redirects --- vercel.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 vercel.json diff --git a/vercel.json b/vercel.json new file mode 100644 index 000000000..308d396df --- /dev/null +++ b/vercel.json @@ -0,0 +1,9 @@ +{ + "redirects": [ + { + "source": "/(.*)", + "destination": "/index.html", + "permanent": true + } + ] +} From fa325f3d76ca128531c14684a698db64497fd9a9 Mon Sep 17 00:00:00 2001 From: jared krajewski Date: Thu, 19 Sep 2024 18:51:27 -0700 Subject: [PATCH 04/15] fixed vercel.json to allow redirects in vercel --- vercel.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vercel.json b/vercel.json index 308d396df..408821b11 100644 --- a/vercel.json +++ b/vercel.json @@ -1,9 +1,8 @@ { - "redirects": [ + "rewrites": [ { "source": "/(.*)", - "destination": "/index.html", - "permanent": true + "destination": "/" } ] } From 5951db7a022150986461ea38d81e569e4bd2f93a Mon Sep 17 00:00:00 2001 From: Ka Hung Lee Date: Thu, 19 Sep 2024 19:41:05 -0700 Subject: [PATCH 05/15] Update webcam modal to include a directional button for user-facing and environment facing cams; Include cancel button to escape from modal; Upate size of modal for devices --- src/components/Modals/WebcamModal.jsx | 32 +++++++++++++++++++++------ 1 file changed, 25 insertions(+), 7 deletions(-) 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

- +
+ + + +
); From da991eb1652a275572f4c18f8288cb08e44b908f Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 25 Sep 2024 12:31:52 -0700 Subject: [PATCH 06/15] Simplifying sorting function --- src/components/Contacts/ContactListTable.jsx | 12 ++--- src/hooks/useTableSort.js | 13 +++--- src/pages/Contacts.jsx | 48 +++++++++++++++++--- 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/components/Contacts/ContactListTable.jsx b/src/components/Contacts/ContactListTable.jsx index 33f328062..9ca771d02 100644 --- a/src/components/Contacts/ContactListTable.jsx +++ b/src/components/Contacts/ContactListTable.jsx @@ -26,15 +26,15 @@ 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(null); const [isEditing, setIsEditing] = useState(false); + const contactWebIds = contacts.map(({ webId }) => webId); + const theme = useTheme(); + const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); const handleSendMessage = (contactId) => { setShowMessageModal(!showMessageModal); @@ -47,14 +47,12 @@ const ContactListTable = ({ contacts, deleteContact, handleDeleteContact, addCon setIsEditing(true); }; - const contactWebIds = contacts.map(({ webId }) => webId); - return ( {isSmallScreen ? ( diff --git a/src/hooks/useTableSort.js b/src/hooks/useTableSort.js index 6b9258ffd..5a32879d5 100644 --- a/src/hooks/useTableSort.js +++ b/src/hooks/useTableSort.js @@ -1,17 +1,18 @@ -// hooks/useSortedData.js import { useState, useEffect } from 'react'; -const useSortedData = (initialData, getFieldValue, initialFieldType) => { +const useSortedData = (getFieldValue, initialFieldType, initialData = []) => { const [fieldType, setFieldType] = useState(initialFieldType); const [sortedData, setSortedData] = useState([]); useEffect(() => { - const sortData = (dataToSort, field) => - [...dataToSort].sort((a, b) => { - const fieldA = getFieldValue(a, field); - const fieldB = getFieldValue(b, field); + const sortData = (field, dataToSort = []) => { + if (!Array.isArray(dataToSort)) return []; + return [...dataToSort].sort((a, b) => { + const fieldA = getFieldValue(a, field) || ''; + const fieldB = getFieldValue(b, field) || ''; return fieldA.localeCompare(fieldB); }); + }; setSortedData(sortData(initialData, fieldType)); }, [fieldType, initialData, getFieldValue]); diff --git a/src/pages/Contacts.jsx b/src/pages/Contacts.jsx index 3560a6394..42869a195 100644 --- a/src/pages/Contacts.jsx +++ b/src/pages/Contacts.jsx @@ -37,8 +37,10 @@ const Contacts = () => { const [processing, setProcessing] = useState(false); const [selectedContactToDelete, setSelectedContactToDelete] = useState(null); const [deleteViaEdit, setDeleteViaEdit] = useState(false); + const [sortValue, setSortValue] = useState('Sort by:'); + const [sortedData, setSortedData] = useState([]); const { - data, + data = [], isLoading, isError, error, @@ -47,12 +49,42 @@ const Contacts = () => { delete: deleteContact } = useContactsList(); const { addNotification } = useNotification(); - const [fieldType, setFieldType] = useState('First Name'); + + const sortData = (value) => { + const sorted = [...data].sort((a, b) => { + if (value === 'Default') { + return data; + } + 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); + }; + + const handleSortChange = (event) => { + const { value } = event.target; + setSortValue(value); + sortData(value); + }; useEffect(() => { refetch(); }, []); + useEffect(() => { + if (data.length > 0) { + setSortedData(data); + } + }, [data]); + const getContactDisplayName = (contact) => { if (!contact) { return 'Unknown Contact'; @@ -104,14 +136,13 @@ const Contacts = () => { > - {/* TODO: Make sorting options functional */} {isSmallScreen && (