Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement add responsive mobile view for documents table#606 #665

Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
f553a9d
Refactor,Style(Documents): DocumentsTable now uses DocumentPreview co…
joshua-cornett Jul 8, 2024
a6bc9d5
refactor(documents): Pull remaining document data for cards. Use elev…
joshua-cornett Jul 9, 2024
e924cd4
refactor(documents): Fix delete. Debugging share in case of filenames…
joshua-cornett Jul 10, 2024
984e067
refactor(documents): Fix share. Adjust document URL encoding to follo…
joshua-cornett Jul 10, 2024
200d98f
[refactor,style](documents): Reintegrate desktop documents table. Imp…
joshua-cornett Jul 11, 2024
e288c86
refactor(documents): Split desktop and mobile views into separate com…
joshua-cornett Jul 16, 2024
08cf44d
Merge branch 'Development' into enhancement-add-responsive-mobile-vie…
joshua-cornett Jul 17, 2024
4c2090a
Merge branch 'Development' into enhancement-add-responsive-mobile-vie…
joshua-cornett Jul 21, 2024
e5f067b
[chore,style](documents - desktop): Complete JSDocs comments for docu…
joshua-cornett Jul 21, 2024
8a7163c
style(mobile documents): Apply mobile contacts styling methodology to…
joshua-cornett Jul 22, 2024
e6ee3bb
fix(documents): In light of the concise mapping of documents and the …
joshua-cornett Jul 23, 2024
cad0534
style(DesktopDocuments): Restore and capitalize headers
joshua-cornett Aug 8, 2024
f963828
chore(DesktopDocuments): Minimized data flow to action items. Extend …
joshua-cornett Aug 10, 2024
a41b965
style(DocumentsMobile): Use FileOpenIcon for Preview, in compliance w…
joshua-cornett Aug 10, 2024
9a6aa7d
style(DocumentsMobile): Add Description column header. Adapt styles t…
joshua-cornett Aug 10, 2024
c71621d
Merge branch 'Development' into enhancement-add-responsive-mobile-vie…
joshua-cornett Aug 25, 2024
d209dbf
style(DocumentsMobile): Move upload and expiration dates to their own…
joshua-cornett Aug 26, 2024
935cab5
style(DocumentsMobile): Remove Type column for consistency with Conta…
joshua-cornett Aug 27, 2024
d71aabc
style(DocumentsMobile): Adjust card style to more closely correspond …
joshua-cornett Aug 27, 2024
cd26b3d
refactor(utils, documents): Add and integrate getTypeText util for us…
joshua-cornett Aug 27, 2024
c5a31a1
[chore, style](DocumentsMobile): Rename 'Name' column to 'Document' i…
joshua-cornett Aug 27, 2024
3e72f85
chore(Documents): Add more thorough commenting
joshua-cornett Aug 27, 2024
fb79527
chore(Documents): Add id to Document typedef
joshua-cornett Aug 27, 2024
13b3dbc
chore(Documents): Add id to Document typedef in other references
joshua-cornett Aug 27, 2024
eaadf57
[chore,style](DocumentsDesktop): Added default cases for unprovided e…
joshua-cornett Aug 27, 2024
cb02e19
chore(Documents): Make comments more consistent with established conv…
joshua-cornett Aug 28, 2024
893cbcc
style(DocumentsMobile): Style more consistently with contacts while s…
joshua-cornett Aug 28, 2024
b6159e4
style(DocumentsMobile): Small tweak to actions button. Move slightly …
joshua-cornett Aug 28, 2024
059c856
style(DocumentsMobile): Small tweak to header. Reintroduced margin to…
joshua-cornett Aug 28, 2024
fd1d8f1
style(DocumentsMobile): Small tweak to description. Add slight margin…
joshua-cornett Aug 28, 2024
e4bcf2f
chore(Documents): Remove inline comments on imports. Move Desktop sty…
joshua-cornett Aug 30, 2024
9f53b0d
[chore,style](Documents): Match header-card margin with card-card mar…
joshua-cornett Aug 31, 2024
436d20b
Merge branch 'Development' into enhancement-add-responsive-mobile-vie…
joshua-cornett Aug 31, 2024
818d3b1
Merge branch 'Development' into enhancement-add-responsive-mobile-vie…
joshua-cornett Aug 31, 2024
1dc61aa
test(Documents): Implement all tests for Documents. Ensure all tests …
joshua-cornett Aug 31, 2024
957ff69
Merge branch 'enhancement-add-responsive-mobile-view-for-documents-ta…
joshua-cornett Aug 31, 2024
d2093cb
[chore, style, test](Documents): Remove document name truncation from…
joshua-cornett Sep 1, 2024
65ff06d
Matching Contact and Document card styling
andycwilliams Sep 2, 2024
8740c02
More style matching
andycwilliams Sep 3, 2024
20f1899
More tweaks
andycwilliams Sep 4, 2024
91a816d
Fixing tests
andycwilliams Sep 4, 2024
3eb29c1
Merge branch 'documentcard-edit' into enhancement-add-responsive-mobi…
andycwilliams Sep 4, 2024
a0972c0
Final styling adjustments to cards in Contacts and Documents
leekahung Sep 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions src/components/Documents/DocumentCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// React Imports
import React, { useState } from 'react';
// Material UI Imports
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import FileOpenIcon from '@mui/icons-material/FileOpen';
import ShareIcon from '@mui/icons-material/Share';
import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined';
import IconButton from '@mui/material/IconButton';
import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';
import MoreVertIcon from '@mui/icons-material/MoreVert';
import Typography from '@mui/material/Typography';

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can remove extra line

/**
* @typedef {object} Document
* @property {string} name - The given name of the document
* @property {string} type - The given type of the document
* @property {string} description - The given description of the document
* @property {string} uploadDate- The upload date of the document
* @property {string} endDate - The expiration date of the document
* @property {string} fileUrl - The file URL of the document
*/

/**
* DocumentCard - Component that contains a document
*
* @memberof Documents
* @name DocumentCard
* @param {object} Props - Component props for Document Preview
* @param {Document} Props.document - The document
* @param {Function} Props.onPreview - The document preview event
* @param {Function} Props.onShare - The document share event
* @param {Function} Props.onDelete - The document delete event
* @returns {React.JSX.Element} React component for DocumentCard
*/
const DocumentCard = ({ document, onShare, onDelete, onPreview }) => {
const [anchorEl, setAnchorEl] = useState(null);
const [openMenu, setOpenMenu] = useState(null);

const handleClick = (event, clickedDocument) => {
setAnchorEl(event.currentTarget);
setOpenMenu(clickedDocument.id);
};
const handleClose = () => {
setAnchorEl(null);
setOpenMenu(null);
};

const handleMenuItemClick = (action, clickedDocument) => () => {
action(clickedDocument);
handleClose();
};

const iconSize = {
height: '24px',
width: '24px'
};

const iconStyling = {
width: '100%'
};

return (
<Box>
<Card
sx={{
my: '5px',
position: 'relative'
}}
>
<CardContent>
<Box>
<Typography variant="body1" component="div" noWrap sx={{ maxWidth: '90%' }}>
{document.name || '[No name given]'}
</Typography>
<Box
sx={{
position: 'absolute',
top: '50%',
right: 5,
transform: 'translateY(-50%)'
}}
>
<IconButton
id="actions-icon-button"
aria-controls={openMenu === document.id ? 'actions-menu' : undefined}
aria-haspopup="true"
aria-expanded={openMenu === document.id ? 'true' : undefined}
onClick={(event) => handleClick(event, document)}
>
<MoreVertIcon />
</IconButton>
</Box>
</Box>
</CardContent>
<Menu
id="actions-menu"
anchorEl={anchorEl}
open={openMenu === document.id}
onClose={handleClose}
MenuListProps={{
'aria-labelledby': 'actions-icon-button'
}}
>
<MenuItem
component={Button}
onClick={handleMenuItemClick(onPreview, document)}
startIcon={<FileOpenIcon sx={iconSize} />}
sx={iconStyling}
>
Preview
</MenuItem>
<MenuItem
component={Button}
onClick={handleMenuItemClick(onShare, document)}
startIcon={<ShareIcon sx={iconSize} />}
sx={iconStyling}
>
Share
</MenuItem>
<MenuItem
component={Button}
onClick={handleMenuItemClick(onDelete, document)}
startIcon={<DeleteOutlineOutlinedIcon sx={iconSize} />}
sx={iconStyling}
>
Delete
</MenuItem>
</Menu>
</Card>
</Box>
);
};

export default DocumentCard;
196 changes: 39 additions & 157 deletions src/components/Documents/DocumentTable.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
// React Imports
import React, { useContext } from 'react';
import React, { useContext, useMemo } from 'react';
import { v4 as uuidv4 } from 'uuid';
// Constants
import DOC_TYPES from '@constants/doc_types';
// Material UI Imports
import Box from '@mui/material/Box';
import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined';
import ShareIcon from '@mui/icons-material/Share';
import FileOpenIcon from '@mui/icons-material/FileOpen';
import {
DataGrid,
GridActionsCellItem,
GridToolbarContainer,
GridToolbarDensitySelector,
GridToolbarFilterButton
} from '@mui/x-data-grid';
import { useMediaQuery } from '@mui/material';

// Context Imports
import { DocumentListContext } from '@contexts';
import { useSession } from '@hooks';
Expand All @@ -24,13 +17,8 @@ import theme from '../../theme';
// Component Imports
import { EmptyListNotification, LoadingAnimation } from '../Notification';

// DataGrid Toolbar
const CustomToolbar = () => (
<GridToolbarContainer>
<GridToolbarFilterButton />
<GridToolbarDensitySelector />
</GridToolbarContainer>
);
import DocumentsMobile from './DocumentsMobile';
import DocumentsDesktop from './DocumentsDesktop';

/**
* DocumentTable - Component that shows the list of documents
Expand All @@ -50,6 +38,8 @@ const DocumentTable = ({ handleAclPermissionsModal, handleSelectDeleteDoc }) =>
const { session } = useSession();
const { documentListObject, loadingDocuments } = useContext(DocumentListContext);

const isMobile = useMediaQuery(theme.breakpoints.down('md'));

/**
* Handles the local display of a document by opening it in a new window.
*
Expand All @@ -74,158 +64,50 @@ const DocumentTable = ({ handleAclPermissionsModal, handleSelectDeleteDoc }) =>
* @returns {Promise<Blob>} A promise that resolves with the Blob of the document.
* @throws {Error} Throws an error if there is an issue fetching the document blob.
*/

const urlFileBlob = await getBlobFromSolid(session, urlToOpen);

// Opens a new window with the Blob URL displaying the document.
window.open(urlFileBlob);
};

const columnTitlesArray = [
{
headerName: 'Name',
field: 'name',
minWidth: 120,
flex: 1,
headerAlign: 'center',
align: 'center'
},
{
headerName: 'Type',
field: 'type',
minWidth: 120,
flex: 1,
headerAlign: 'center',
align: 'center'
},
{
headerName: 'Description',
field: 'description',
minWidth: 120,
flex: 1,
headerAlign: 'center',
align: 'center'
},
{
headerName: 'Upload Date',
field: 'upload date',
minWidth: 120,
flex: 1,
headerAlign: 'center',
align: 'center'
},
{
headerName: 'Expiration Date',
field: 'expiration date',
minWidth: 120,
flex: 1,
headerAlign: 'center',
align: 'center'
},
{
headerName: 'Preview File',
field: 'preview file',
minWidth: 100,
flex: 1,
headerAlign: 'center',
align: 'center',
sortable: false,
filterable: false,
renderCell: (fileUrl) => (
<GridActionsCellItem
key={String(fileUrl)}
icon={<FileOpenIcon />}
onClick={() => handleShowDocumentLocal(fileUrl)}
label="Preview"
/>
)
},
{
headerName: 'Sharing',
field: 'sharing',
type: 'actions',
minWidth: 80,
flex: 1,
headerAlign: 'center',
align: 'center',
getActions: (data) => [
<GridActionsCellItem
icon={<ShareIcon />}
onClick={() => handleAclPermissionsModal('document', data.row.id, data.row.type)}
label="Share"
/>
]
},
{
headerName: 'Delete',
field: 'actions',
type: 'actions',
minWidth: 80,
flex: 1,
headerAlign: 'center',
align: 'center',
getActions: (data) => [
<GridActionsCellItem
icon={<DeleteOutlineOutlinedIcon />}
onClick={() => handleSelectDeleteDoc(data.row.delete)}
label="Delete"
/>
]
}
];

// Updates type value to use DOC_TYPES for formatting the string
const mappingType = (type) => DOC_TYPES[type] || type;

// Map types for each document in the array
const mappedDocuments = documentListObject?.docList.map((document) => ({
...document,
type: mappingType(document.type)
}));
const documents = useMemo(
() =>
documentListObject?.docList.map((document) => ({
id: uuidv4(), // Generate a UUID (a unique ID)
type: mappingType(document.type),
...document
})),
[documentListObject?.docList]
);

const handlers = {
onShare: handleAclPermissionsModal,
onDelete: handleSelectDeleteDoc,
onPreview: handleShowDocumentLocal
};

const determineDocumentsTable = mappedDocuments?.length ? (
// Render if documents
<Box sx={{ margin: '20px 0', width: '90vw', height: '500px' }}>
<DataGrid
columns={columnTitlesArray}
rows={mappedDocuments.map((document) => ({
id: document.name,
type: document.type,
name: document.name,
description: document.description,
delete: document,
'upload date': document?.uploadDate.toLocaleDateString(),
'expiration date': document?.endDate?.toLocaleDateString(),
'preview file': document.fileUrl
}))}
pageSizeOptions={[10]}
initialState={{
pagination: {
paginationModel: { pageSize: 10, page: 0 }
}
}}
slots={{
toolbar: CustomToolbar
}}
disableColumnMenu
disableRowSelectionOnClick
sx={{
'.MuiDataGrid-columnHeader': {
background: theme.palette.primary.light,
color: 'white'
},
'.MuiDataGrid-columnSeparator': {
display: 'none'
}
}}
/>
if (!documents?.length) return <EmptyListNotification type="documents" />;
if (loadingDocuments) return <LoadingAnimation loadingItem="documents" />;
return (
<Box
sx={{
margin: '20px 0',
width: '95vw',
height: '500px'
}}
>
{isMobile ? (
<DocumentsMobile documents={documents} handlers={handlers} />
) : (
<DocumentsDesktop documents={documents} handlers={handlers} />
)}
</Box>
) : (
// Render if no documents
<EmptyListNotification type="documents" />
);

// MAIN RETURN OF COMPONENT
return loadingDocuments ? <LoadingAnimation loadingItem="documents" /> : determineDocumentsTable;
};

export default DocumentTable;
Loading
Loading