Sfoglia il codice sorgente

done litle bit about lists

unknown 2 anni fa
parent
commit
6caebdc2a8

File diff suppressed because it is too large
+ 1 - 1
.eslintcache


+ 48 - 0
package-lock.json

@@ -35,6 +35,7 @@
         "modern-normalize": "^1.0.0",
         "react": "^17.0.1",
         "react-audio-player": "^0.17.0",
+        "react-copy-to-clipboard": "^5.0.4",
         "react-dom": "^17.0.1",
         "react-dropzone": "^12.0.1",
         "react-file-viewer": "^1.2.1",
@@ -6229,6 +6230,14 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/copy-to-clipboard": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz",
+      "integrity": "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==",
+      "dependencies": {
+        "toggle-selection": "^1.0.6"
+      }
+    },
     "node_modules/core-js": {
       "version": "3.7.0",
       "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.7.0.tgz",
@@ -17870,6 +17879,18 @@
         "react-dom": ">=16"
       }
     },
+    "node_modules/react-copy-to-clipboard": {
+      "version": "5.0.4",
+      "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.4.tgz",
+      "integrity": "sha512-IeVAiNVKjSPeGax/Gmkqfa/+PuMTBhutEvFUaMQLwE2tS0EXrAdgOpWDX26bWTXF3HrioorR7lr08NqeYUWQCQ==",
+      "dependencies": {
+        "copy-to-clipboard": "^3",
+        "prop-types": "^15.5.8"
+      },
+      "peerDependencies": {
+        "react": "^15.3.0 || ^16.0.0 || ^17.0.0"
+      }
+    },
     "node_modules/react-dev-utils": {
       "version": "11.0.1",
       "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.1.tgz",
@@ -21104,6 +21125,11 @@
         "node": ">=8.0"
       }
     },
+    "node_modules/toggle-selection": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
+      "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI="
+    },
     "node_modules/toidentifier": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
@@ -28866,6 +28892,14 @@
       "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
       "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
     },
+    "copy-to-clipboard": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz",
+      "integrity": "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==",
+      "requires": {
+        "toggle-selection": "^1.0.6"
+      }
+    },
     "core-js": {
       "version": "3.7.0",
       "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.7.0.tgz",
@@ -38348,6 +38382,15 @@
         "prop-types": "^15.7.2"
       }
     },
+    "react-copy-to-clipboard": {
+      "version": "5.0.4",
+      "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.4.tgz",
+      "integrity": "sha512-IeVAiNVKjSPeGax/Gmkqfa/+PuMTBhutEvFUaMQLwE2tS0EXrAdgOpWDX26bWTXF3HrioorR7lr08NqeYUWQCQ==",
+      "requires": {
+        "copy-to-clipboard": "^3",
+        "prop-types": "^15.5.8"
+      }
+    },
     "react-dev-utils": {
       "version": "11.0.1",
       "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.1.tgz",
@@ -41050,6 +41093,11 @@
         "is-number": "^7.0.0"
       }
     },
+    "toggle-selection": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
+      "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI="
+    },
     "toidentifier": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",

+ 1 - 0
package.json

@@ -31,6 +31,7 @@
     "modern-normalize": "^1.0.0",
     "react": "^17.0.1",
     "react-audio-player": "^0.17.0",
+    "react-copy-to-clipboard": "^5.0.4",
     "react-dom": "^17.0.1",
     "react-dropzone": "^12.0.1",
     "react-file-viewer": "^1.2.1",

+ 16 - 12
src/components/HomePage/RightBar/HeaderBar/RightLists/CredentialsList/ProfileLists/AudioList/index.tsx

@@ -3,6 +3,7 @@ import ListItem from '@mui/material/ListItem';
 import ListItemText from '@mui/material/ListItemText';
 import ListItemAvatar from '@mui/material/ListItemAvatar';
 import LibraryMusicIcon from '@mui/icons-material/LibraryMusic';
+import Divider from '@mui/material/Divider';
 import { makeStyles } from '@material-ui/core'
 
 import AlertInfo from '../../../../../../../reusableComponents/AlertInfo';
@@ -23,18 +24,21 @@ const AudioList = ({ messagesMemo }: { messagesMemo: TMessages }) => {
     const filteredMessagesMemo =  messagesMemo.filter(({type}) => type === 'audio')
     return filteredMessagesMemo.length > 0 ?(
       <List>
-        {filteredMessagesMemo.map(({message,createdAt,fullType}) => 
-          <ListItem key={createdAt} alignItems="flex-start">
-            <ListItemAvatar>
-              <LibraryMusicIcon onClick={() =>
-                handleDownload(`http://localhost:3000/${message}`, fullType)}
-                className={classes.folderIcon} fontSize='large' />
-            </ListItemAvatar>
-            <ListItemText
-              primary={fullType}
-              secondary={timeStampEU(createdAt)}
-            />
-        </ListItem>)}
+        {filteredMessagesMemo.map(({ message, createdAt, fullType }) =>
+          <>
+            <ListItem key={createdAt} alignItems="flex-start">
+              <ListItemAvatar>
+                <LibraryMusicIcon onClick={() =>
+                  handleDownload(`http://localhost:3000/${message}`, fullType)}
+                  className={classes.folderIcon} fontSize='large' />
+              </ListItemAvatar>
+              <ListItemText
+                primary={fullType}
+                secondary={timeStampEU(createdAt)}
+               />
+            </ListItem>
+            <Divider/>
+        </>)}
     </List>
    ): <AlertInfo name='You do not have Audio yet!'/>  
 }

+ 16 - 12
src/components/HomePage/RightBar/HeaderBar/RightLists/CredentialsList/ProfileLists/FilesList/index.tsx

@@ -3,6 +3,7 @@ import ListItem from '@mui/material/ListItem';
 import ListItemText from '@mui/material/ListItemText';
 import ListItemAvatar from '@mui/material/ListItemAvatar';
 import FolderIcon from '@mui/icons-material/Folder';
+import Divider from '@mui/material/Divider';
 import { makeStyles } from '@material-ui/core'
 
 import AlertInfo from '../../../../../../../reusableComponents/AlertInfo';
@@ -23,18 +24,21 @@ const FilesList = ({ messagesMemo }: { messagesMemo: TMessages }) => {
     const filteredMessagesMemo =  messagesMemo.filter(({type}) => type !== 'text')
     return filteredMessagesMemo.length > 0 ?(
       <List>
-        {filteredMessagesMemo.map(({message,createdAt,fullType}) => 
-          <ListItem key={createdAt} alignItems="flex-start">
-            <ListItemAvatar>
-              <FolderIcon onClick={() =>
-                handleDownload(`http://localhost:3000/${message}`, fullType)}
-                className={classes.folderIcon} fontSize='large' />
-            </ListItemAvatar>
-            <ListItemText
-              primary={fullType}
-              secondary={timeStampEU(createdAt)}
-            />
-        </ListItem>)}
+        {filteredMessagesMemo.map(({ message, createdAt, fullType }) =>
+          <>
+            <ListItem key={createdAt} alignItems="flex-start">
+              <ListItemAvatar>
+                <FolderIcon onClick={() =>
+                  handleDownload(`http://localhost:3000/${message}`, fullType)}
+                  className={classes.folderIcon} fontSize='large' />
+              </ListItemAvatar>
+              <ListItemText
+                primary={fullType}
+                secondary={timeStampEU(createdAt)}
+              />
+            </ListItem>
+            <Divider/>
+        </>)}
     </List>
    ): <AlertInfo name='You do not have Files yet!'/>  
 }

+ 38 - 4
src/components/HomePage/RightBar/HeaderBar/RightLists/CredentialsList/ProfileLists/MediaList/MediListItem/index.tsx

@@ -2,7 +2,8 @@
 import { makeStyles } from '@material-ui/core'
 import { useState } from 'react';
 import ImageListItem from '@mui/material/ImageListItem';
-import { handleDownload } from '../../../../../../../../../helpers'
+import DownloadForOfflineIcon from '@mui/icons-material/DownloadForOffline';
+import { handleDownload,timeStampEU } from '../../../../../../../../../helpers'
 
 const useStyles = makeStyles({ 
   overlay: {
@@ -21,8 +22,37 @@ const useStyles = makeStyles({
     alignContent: 'center',
     alignItems: 'center'
   },
+  wrapper: {
+    width: '40%',
+    height: 'auto',
+    position: 'relative'
+  },
+  downloadIcon: {
+    position: 'absolute',
+    content: '',
+    right: 0,
+    top: -40,
+    cursor: 'pointer',
+    color: '#e9e7e7',
+    padding: 0,
+    borderRadius: '50%',
+    '&:hover': {
+      backgroundColor: '#ffffff',
+      color: '#b8b7b7',
+    }
+  },
+  time: {
+    position: 'absolute',
+    content: '',    
+    color: '#ffffff',
+    top: -30,
+    left: 0,
+    borderRadius: 10,
+    padding:'2px 6px 2px 6px',
+    backgroundColor:'#707070'
+  }
 });
-const MediaListItem = ({ message,fullType }: { message: string,fullType:string }) => {
+const MediaListItem = ({ message,fullType,updatedAt }: { message: string,fullType:string,updatedAt:string }) => {
   const classes = useStyles();
   const [watch, setWatch] = useState<boolean>(false)
   const handleOpenWatch = () => !watch && setWatch(true)
@@ -32,8 +62,12 @@ const MediaListItem = ({ message,fullType }: { message: string,fullType:string }
   
   return (watch ?
     <div onClick={handleCloseWatch} id='overlay' className={classes.overlay}>
-      <img onClick={() => handleDownload(url, fullType)}
-        width='40%' alt='imageItem' src={url} style={{cursor:'pointer'}} />
+      <div className={classes.wrapper}>
+        <span className={classes.time}>{timeStampEU(updatedAt)}</span>
+        <DownloadForOfflineIcon className={classes.downloadIcon} fontSize='large'
+         onClick={() => handleDownload(url, fullType)}/>
+        <img width='100%' height='auto' alt='imageItem' src={url} />
+       </div>
     </div> :
     <ImageListItem>
       <img onClick={handleOpenWatch} style={{cursor:'pointer'}}

+ 3 - 4
src/components/HomePage/RightBar/HeaderBar/RightLists/CredentialsList/ProfileLists/MediaList/index.tsx

@@ -1,6 +1,5 @@
-
 import ImageList from '@mui/material/ImageList';
-import MediaListItem from './MediListItem';
+import MediaListItem from './MediaListItem';
 
 import AlertInfo from '../../../../../../../reusableComponents/AlertInfo';
 import { TMessages } from '../../../../../../../../typescript/redux/messages/types'
@@ -9,8 +8,8 @@ const MediaList = ({ messagesMemo }: { messagesMemo: TMessages }) => {
   const filteredMessagesMemo =  messagesMemo.filter(({ type }) => type === 'image')
   return filteredMessagesMemo.length > 0 ?(
       <ImageList sx={{ width: '100%', height: 'auto' }} cols={3} rowHeight={164}>
-        {filteredMessagesMemo.map(({message,createdAt,fullType}) => 
-          <MediaListItem key={createdAt} message={message} fullType={fullType}/>)}
+        {filteredMessagesMemo.map(({message,createdAt,fullType,updatedAt}) => 
+          <MediaListItem key={createdAt} message={message} fullType={fullType} updatedAt={updatedAt}/>)}
       </ImageList>
    ): <AlertInfo name='You do not have Media yet!'/>  
 }

+ 14 - 20
src/components/HomePage/RightBar/HeaderBar/RightLists/CredentialsList/ProfileLists/TextList/index.tsx

@@ -3,38 +3,32 @@ import ListItem from '@mui/material/ListItem';
 import ListItemText from '@mui/material/ListItemText';
 import ListItemAvatar from '@mui/material/ListItemAvatar';
 import Avatar from '@mui/material/Avatar';
-import { makeStyles } from '@material-ui/core'
+import Divider from '@mui/material/Divider';
 
 import AlertInfo from '../../../../../../../reusableComponents/AlertInfo';
 import { timeStampEU,firstLetter } from '../../../../../../../../helpers'
 import { TMessages } from '../../../../../../../../typescript/redux/messages/types'
 
-const useStyles = makeStyles({
-    folderIcon: {
-      color: '#54b0fc',
-      cursor: 'pointer',
-      '&:hover': {
-        color: '#016cc3'
-      },
-    },
-})
 const TextList = ({ messagesMemo }: { messagesMemo: TMessages }) => {
-    const classes = useStyles()
-    const filteredMessagesMemo =  messagesMemo.filter(({type}) => type === 'text')
-    return filteredMessagesMemo.length > 0 ?(
+
+  const filteredMessagesMemo =  messagesMemo.filter(({type}) => type === 'text')
+   return filteredMessagesMemo.length > 0 ?(
       <List>
-        {filteredMessagesMemo.map(({message,createdAt,lastName,name,color}) => 
+       {filteredMessagesMemo.map(({ message, createdAt, lastName, name, color, avatarUrl }) =>
+         <>
           <ListItem key={createdAt} alignItems="flex-start">
             <ListItemAvatar>
-              <Avatar alt="Credentials" style={{background: color}}>
-                {`${firstLetter(name)}${firstLetter(lastName)}`}
+              <Avatar alt={name} src={avatarUrl?`http://localhost:3000/${avatarUrl}`:undefined}
+                  sx={{ background: color, width: 38, height: 38,marginRight:2}}>
+                  {`${firstLetter(name)}${firstLetter(lastName)}`}
               </Avatar>
             </ListItemAvatar>
-            <ListItemText
-              primary={message}
-              secondary={timeStampEU(createdAt)}
+             <ListItemText style={{ wordBreak: 'break-word' }} primary={message}
+               secondary={timeStampEU(createdAt)} secondaryTypographyProps={{color: '#020202',paddingTop:0.5}}
             />
-        </ListItem>)}
+          </ListItem>
+          <Divider />
+        </>)}
     </List>
    ): <AlertInfo name='You do not have Text yet!'/>  
 }

+ 46 - 0
src/components/HomePage/RightBar/HeaderBar/RightLists/CredentialsList/ProfileLists/VideoList/index.tsx

@@ -0,0 +1,46 @@
+import List from '@mui/material/List';
+import ListItem from '@mui/material/ListItem';
+import ListItemText from '@mui/material/ListItemText';
+import ListItemAvatar from '@mui/material/ListItemAvatar';
+import VideoLibraryIcon from '@mui/icons-material/VideoLibrary';
+import Divider from '@mui/material/Divider';
+import { makeStyles } from '@material-ui/core'
+
+import AlertInfo from '../../../../../../../reusableComponents/AlertInfo';
+import { timeStampEU,handleDownload } from '../../../../../../../../helpers'
+import { TMessages } from '../../../../../../../../typescript/redux/messages/types'
+
+const useStyles = makeStyles({
+    folderIcon: {
+      color: '#54b0fc',
+      cursor: 'pointer',
+      '&:hover': {
+        color: '#016cc3'
+      },
+    },
+})
+const VideoList = ({ messagesMemo }: { messagesMemo: TMessages }) => {
+  const classes = useStyles()
+    const filteredMessagesMemo =  messagesMemo.filter(({type}) => type === 'video')
+    return filteredMessagesMemo.length > 0 ?(
+      <List>
+        {filteredMessagesMemo.map(({ message, createdAt, fullType }) =>
+          <>
+            <ListItem key={createdAt} alignItems="flex-start">
+              <ListItemAvatar>
+                <VideoLibraryIcon onClick={() =>
+                  handleDownload(`http://localhost:3000/${message}`, fullType)}
+                  className={classes.folderIcon} fontSize='large' />
+              </ListItemAvatar>
+              <ListItemText
+                primary={fullType}
+                secondary={timeStampEU(createdAt)}
+               />
+            </ListItem>
+            <Divider/>
+        </>)}
+    </List>
+   ): <AlertInfo name='You do not have Audio yet!'/>  
+}
+
+export default VideoList

+ 21 - 13
src/components/HomePage/RightBar/HeaderBar/RightLists/CredentialsList/ProfileLists/index.tsx

@@ -8,29 +8,35 @@ import AudioList from './AudioList';
 import MediaList from './MediaList';
 import FilesList from './FilesList';
 import TextList from './TextList';
+import VideoList from './VideoList'
 import { getMessagesMemo } from '../../../../../../../redux/messages/selector'
+import { handleSort } from '../../../../../../../helpers';
+import { TMessages } from '../../../../../../../typescript/redux/messages/types'
 
 const useStyles = makeStyles({
     bottomNavigation: {
         boxShadow: '0px 1px 1px 1px rgba(120,120,120,0.63)',
-        marginBottom: 20
     },
     icon: {
-        marginBottom:0,
+        fontSize: 17,
+        lineHeight: 0,
+        marginBottom: 0,
+        fontWeight:600
     },
     underline: {
-        fontSize: 30,
-        lineHeight:0
+        fontSize: 45,
+        lineHeight: 0,
     },
 })
 
-const ProfileLists = () => {
+const ProfileLists = ({sort}:{sort:boolean}) => {
     const classes = useStyles()
     const messagesMemo = useSelector(getMessagesMemo)
     const [isActive, setIsActive] = useState<number>(0)
     const handleIsActive = (_e: React.SyntheticEvent<Element, Event>, newValue: number): void => setIsActive(newValue)
     const Icon = ({ name }: { name: string }) => <span className={classes.icon}>{name}</span>
     const Label = () => <span className={classes.underline}>__</span>
+    const sortedMessages:TMessages = handleSort('updatedAt',messagesMemo,sort)
     return (
     <>
       <BottomNavigation
@@ -38,17 +44,19 @@ const ProfileLists = () => {
         value={isActive}
         onChange={handleIsActive}
         className={classes.bottomNavigation}
-      >
+        >
+            <BottomNavigationAction label={<Label/>} icon={<Icon name='Files' />} />   
             <BottomNavigationAction label={<Label/>} icon={<Icon name='Media' />} />
-            <BottomNavigationAction label={<Label/>} icon={<Icon name='Files' />} />
             <BottomNavigationAction label={<Label/>} icon={<Icon name='Text' />} />
-            <BottomNavigationAction label={<Label/>} icon={<Icon name='Music' />} />
+            <BottomNavigationAction label={<Label />} icon={<Icon name='Audio' />} />
+            <BottomNavigationAction label={<Label/>} icon={<Icon name='Video' />} />
 
-        </BottomNavigation>
-            {isActive === 0 && <MediaList messagesMemo={messagesMemo}/>}
-            {isActive === 1 && <FilesList messagesMemo={messagesMemo}/>}
-            {isActive === 2 && <TextList messagesMemo={messagesMemo}/>}
-            {isActive === 3 && <AudioList messagesMemo={messagesMemo}/>}
+            </BottomNavigation>
+            {isActive === 0 && <FilesList messagesMemo={sortedMessages}/>}            
+            {isActive === 1 && <MediaList messagesMemo={sortedMessages}/>}
+            {isActive === 2 && <TextList messagesMemo={sortedMessages}/>}
+            {isActive === 3 && <AudioList messagesMemo={sortedMessages} />}
+            {isActive === 4 && <VideoList messagesMemo={sortedMessages}/>}
     </>      
     )
 }

+ 13 - 2
src/components/HomePage/RightBar/HeaderBar/RightLists/CredentialsList/ProfileMenu/index.tsx

@@ -6,7 +6,9 @@ import ListItemText from '@mui/material/ListItemText';
 import ListItemIcon from '@mui/material/ListItemIcon';
 import PhoneIcon from '@mui/icons-material/Phone';
 import NotificationsIcon from '@mui/icons-material/Notifications';
+import SortIcon from '@mui/icons-material/Sort';
 import Switch from '@mui/material/Switch';
+import Divider from '@mui/material/Divider';
 import { makeStyles } from '@material-ui/core'
 
 import { getChat } from '../../../../../../../redux/chat/selector'
@@ -15,7 +17,6 @@ import { muteChat } from '../../../../../../../api-data'
 const useStyles = makeStyles({
     container: {
     width: '100%',
-    marginBottom:16
     },
     list: {
       background:'#fdfdfd'
@@ -27,7 +28,7 @@ const useStyles = makeStyles({
 
 const label = { inputProps: { 'aria-label': 'Switch demo' } };
 
-const ProfileMenu = () => {
+const ProfileMenu = ({sort,handleSort}:{sort:boolean,handleSort: () => void}) => {
   const classes = useStyles()
   const { number, mute, companionId } = useSelector(getChat)
   const handleMute = () => muteChat(companionId)
@@ -40,6 +41,7 @@ const ProfileMenu = () => {
           </ListItemIcon>
           <ListItemText primary={number} secondary='Phone'/>
         </MenuItem>
+        <Divider variant="inset"/>
         <MenuItem onClick={() => console.log('clicked Notification')}>
           <ListItemIcon className={classes.listIcon}>
             <NotificationsIcon fontSize="medium" />
@@ -47,6 +49,15 @@ const ProfileMenu = () => {
           <ListItemText primary='Notification' />
           <Switch onClick={handleMute} {...label} defaultChecked={!mute} />
         </MenuItem>
+        <Divider variant="inset"/>
+        <MenuItem onClick={() => console.log('clicked Notification')}>
+          <ListItemIcon className={classes.listIcon}>
+            <SortIcon fontSize="medium" />
+          </ListItemIcon>
+          <ListItemText primary={`Sort by Date`} />
+          <Switch onClick={handleSort} {...label} defaultChecked={sort} />
+        </MenuItem>
+        <Divider/>
       </MenuList>
     </Paper>
   );

+ 5 - 2
src/components/HomePage/RightBar/HeaderBar/RightLists/CredentialsList/index.tsx

@@ -1,4 +1,5 @@
 import { makeStyles } from '@material-ui/core'
+import { useState } from 'react'
 import ToolBar from './ToolBar'
 import ProfilePicture from './ProfilePicture'
 import ProfileMenu from './ProfileMenu'
@@ -20,13 +21,15 @@ const useStyles = makeStyles({
 
 const CredentialsList= () => {
   const classes = useStyles()
+  const [sort, setSort] = useState<boolean>(false)
+  const handleSort = () => setSort(!sort)
     return (
     <div>
         <ToolBar />
         <div className={classes.containerAbsolute}>
           <ProfilePicture />
-          <ProfileMenu />
-          <ProfileLists/>
+          <ProfileMenu sort={sort} handleSort={handleSort}/>
+          <ProfileLists sort={sort}/>
      </div>
    </div>
   )

+ 14 - 2
src/helpers/index.ts

@@ -87,7 +87,18 @@ const playNotificationWithoutPermission = (url: string) => {
     .catch(reason => console.error(`Audio permissions denied: ${reason}`));
 }
 
-const handleDownload = async (url: string,type:string) => await FileSaver.saveAs(url, type);
+const handleDownload = async (url: string, type: string) => await FileSaver.saveAs(url, type);
+
+const handleSort = (sortBy: string, data: any,sort:boolean): any => {
+    return [...data].sort(function (a: any, b: any) {
+      if (sort?a[sortBy] > b[sortBy]:a[sortBy] < b[sortBy]) {
+        return -1;
+      } else if (sort?a[sortBy] < b[sortBy]:a[sortBy] > b[sortBy]) {
+        return 1;
+      }
+      return 0;
+    });
+};
 
 
 
@@ -102,5 +113,6 @@ export {
   playNotification,
   notification,
   playNotificationWithoutPermission,
-  handleDownload
+  handleDownload,
+  handleSort
 }