2024-08-06 12:42:21 +02:00
|
|
|
import { Button, Divider, TextField, Tooltip } from '@mui/material'
|
2024-06-28 14:24:14 +05:00
|
|
|
import JSZip from 'jszip'
|
2024-08-06 12:42:21 +02:00
|
|
|
import { useEffect, useRef, useState } from 'react'
|
2024-05-14 14:27:05 +05:00
|
|
|
import { useNavigate } from 'react-router-dom'
|
2024-06-28 14:24:14 +05:00
|
|
|
import { toast } from 'react-toastify'
|
2024-07-05 13:38:04 +05:00
|
|
|
import { useAppSelector } from '../../hooks'
|
2024-06-13 11:47:28 +05:00
|
|
|
import { appPrivateRoutes, appPublicRoutes } from '../../routes'
|
2024-08-06 12:42:21 +02:00
|
|
|
import { Meta, ProfileMetadata } from '../../types'
|
|
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
2024-06-28 14:24:14 +05:00
|
|
|
import {
|
2024-08-06 12:42:21 +02:00
|
|
|
faAdd,
|
|
|
|
faFilter,
|
|
|
|
faFilterCircleXmark,
|
|
|
|
faSearch
|
|
|
|
} from '@fortawesome/free-solid-svg-icons'
|
|
|
|
import { Select } from '../../components/Select'
|
|
|
|
import { DisplaySigit } from '../../components/DisplaySigit'
|
|
|
|
|
2024-07-30 10:28:57 +02:00
|
|
|
import { Container } from '../../components/Container'
|
2024-08-06 12:42:21 +02:00
|
|
|
import styles from './style.module.scss'
|
|
|
|
|
|
|
|
// Unsupported Filter options are commented
|
|
|
|
const FILTERS = [
|
|
|
|
'Show all',
|
|
|
|
// 'Drafts',
|
|
|
|
'In-progress',
|
|
|
|
'Completed'
|
|
|
|
// 'Archived'
|
|
|
|
] as const
|
|
|
|
type Filter = (typeof FILTERS)[number]
|
|
|
|
|
|
|
|
const SORT_BY = [
|
|
|
|
{
|
|
|
|
label: 'Newest',
|
|
|
|
value: 'desc'
|
|
|
|
},
|
|
|
|
{ label: 'Oldest', value: 'asc' }
|
|
|
|
] as const
|
|
|
|
type Sort = (typeof SORT_BY)[number]['value']
|
2024-04-08 17:45:51 +05:00
|
|
|
|
|
|
|
export const HomePage = () => {
|
2024-05-14 14:27:05 +05:00
|
|
|
const navigate = useNavigate()
|
2024-06-13 11:47:28 +05:00
|
|
|
const fileInputRef = useRef<HTMLInputElement>(null)
|
2024-07-05 13:38:04 +05:00
|
|
|
const [sigits, setSigits] = useState<Meta[]>([])
|
2024-06-28 14:24:14 +05:00
|
|
|
const [profiles, setProfiles] = useState<{ [key: string]: ProfileMetadata }>(
|
|
|
|
{}
|
|
|
|
)
|
2024-07-05 13:38:04 +05:00
|
|
|
const usersAppData = useAppSelector((state) => state.userAppData)
|
2024-06-28 14:24:14 +05:00
|
|
|
|
|
|
|
useEffect(() => {
|
2024-07-05 13:38:04 +05:00
|
|
|
if (usersAppData) {
|
|
|
|
setSigits(Object.values(usersAppData.sigits))
|
|
|
|
}
|
|
|
|
}, [usersAppData])
|
2024-06-13 11:47:28 +05:00
|
|
|
|
|
|
|
const handleUploadClick = () => {
|
|
|
|
if (fileInputRef.current) {
|
|
|
|
fileInputRef.current.click()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const handleFileChange = async (
|
|
|
|
event: React.ChangeEvent<HTMLInputElement>
|
|
|
|
) => {
|
|
|
|
const file = event.target.files?.[0]
|
|
|
|
if (file) {
|
|
|
|
// Check if the file extension is .sigit.zip
|
|
|
|
const fileName = file.name
|
|
|
|
const fileExtension = fileName.slice(-10) // ".sigit.zip" has 10 characters
|
|
|
|
if (fileExtension === '.sigit.zip') {
|
|
|
|
const zip = await JSZip.loadAsync(file).catch((err) => {
|
|
|
|
console.log('err in loading zip file :>> ', err)
|
|
|
|
toast.error(err.message || 'An error occurred in loading zip file.')
|
|
|
|
return null
|
|
|
|
})
|
|
|
|
|
|
|
|
if (!zip) return
|
|
|
|
|
|
|
|
// navigate to sign page if zip contains keys.json
|
|
|
|
if ('keys.json' in zip.files) {
|
|
|
|
return navigate(appPrivateRoutes.sign, {
|
|
|
|
state: { uploadedZip: file }
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// navigate to verify page if zip contains meta.json
|
|
|
|
if ('meta.json' in zip.files) {
|
|
|
|
return navigate(appPublicRoutes.verify, {
|
|
|
|
state: { uploadedZip: file }
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
toast.error('Invalid zip file')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// navigate to create page
|
|
|
|
navigate(appPrivateRoutes.create, { state: { uploadedFile: file } })
|
|
|
|
}
|
|
|
|
}
|
2024-04-08 17:45:51 +05:00
|
|
|
|
2024-08-06 12:42:21 +02:00
|
|
|
const [filter, setFilter] = useState<Filter>('Show all')
|
|
|
|
const [isFilterVisible, setIsFilterVisible] = useState(true)
|
|
|
|
const [sort, setSort] = useState<Sort>('asc')
|
|
|
|
|
2024-04-08 17:45:51 +05:00
|
|
|
return (
|
2024-07-30 10:28:57 +02:00
|
|
|
<Container className={styles.container}>
|
2024-08-06 12:42:21 +02:00
|
|
|
<div className={styles.header}>
|
|
|
|
{isFilterVisible && (
|
|
|
|
<>
|
|
|
|
<Select
|
2024-08-06 14:07:41 +02:00
|
|
|
name={'filter-select'}
|
2024-08-06 12:42:21 +02:00
|
|
|
setValue={setFilter}
|
|
|
|
options={FILTERS.map((f) => {
|
|
|
|
return {
|
|
|
|
label: f,
|
|
|
|
value: f
|
|
|
|
}
|
|
|
|
})}
|
|
|
|
/>
|
|
|
|
<Select
|
2024-08-06 14:07:41 +02:00
|
|
|
name={'sort-select'}
|
2024-08-06 12:42:21 +02:00
|
|
|
setValue={setSort}
|
|
|
|
options={SORT_BY.map((s) => {
|
|
|
|
return { ...s }
|
|
|
|
})}
|
|
|
|
/>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
<div className={styles.actionButtons}>
|
|
|
|
<div className={styles.search}>
|
|
|
|
<TextField
|
|
|
|
placeholder="Search"
|
|
|
|
size="small"
|
|
|
|
sx={{
|
|
|
|
fontSize: '16px',
|
|
|
|
height: '34px',
|
|
|
|
borderTopLeftRadius: 'var(----mui-shape-borderRadius)',
|
|
|
|
borderBottomLeftRadius: 'var(----mui-shape-borderRadius)',
|
|
|
|
'& .MuiInputBase-root': {
|
|
|
|
borderTopRightRadius: 0,
|
|
|
|
borderBottomRightRadius: 0
|
|
|
|
},
|
|
|
|
'& .MuiInputBase-input': {
|
|
|
|
padding: '5.5px 14px'
|
|
|
|
},
|
|
|
|
'& .MuiOutlinedInput-notchedOutline': {
|
|
|
|
display: 'none'
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
<Button
|
|
|
|
sx={{
|
|
|
|
minWidth: '44px',
|
|
|
|
padding: '10px 12px',
|
|
|
|
borderTopLeftRadius: 0,
|
|
|
|
borderBottomLeftRadius: 0
|
|
|
|
}}
|
|
|
|
variant={'contained'}
|
|
|
|
>
|
|
|
|
<FontAwesomeIcon icon={faSearch} />
|
|
|
|
</Button>
|
|
|
|
</div>
|
|
|
|
<Divider orientation="vertical" variant="middle" flexItem />
|
|
|
|
<Tooltip title="Toggle Filter" arrow>
|
|
|
|
<Button
|
|
|
|
sx={{
|
|
|
|
minWidth: '44px',
|
|
|
|
padding: '10px 12px'
|
|
|
|
}}
|
|
|
|
variant={'contained'}
|
|
|
|
onClick={() => setIsFilterVisible((v) => !v)}
|
|
|
|
>
|
|
|
|
{isFilterVisible ? (
|
|
|
|
<FontAwesomeIcon icon={faFilterCircleXmark} />
|
|
|
|
) : (
|
|
|
|
<FontAwesomeIcon icon={faFilter} />
|
|
|
|
)}
|
|
|
|
</Button>
|
|
|
|
</Tooltip>
|
|
|
|
<Tooltip title="Upload" arrow>
|
|
|
|
<Button
|
|
|
|
sx={{
|
|
|
|
minWidth: '44px',
|
|
|
|
padding: '10px 12px'
|
|
|
|
}}
|
|
|
|
component={'label'}
|
|
|
|
htmlFor="fileUpload"
|
|
|
|
variant={'contained'}
|
|
|
|
onClick={handleUploadClick}
|
|
|
|
>
|
|
|
|
<FontAwesomeIcon icon={faAdd} />
|
|
|
|
</Button>
|
|
|
|
</Tooltip>
|
2024-07-30 10:28:57 +02:00
|
|
|
<input
|
2024-08-06 12:42:21 +02:00
|
|
|
id="fileUpload"
|
2024-07-30 10:28:57 +02:00
|
|
|
type="file"
|
2024-08-06 12:42:21 +02:00
|
|
|
hidden
|
2024-07-30 10:28:57 +02:00
|
|
|
ref={fileInputRef}
|
|
|
|
onChange={handleFileChange}
|
|
|
|
/>
|
2024-08-06 12:42:21 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className={styles.dropzone}>
|
|
|
|
<div>Click or drag files to upload!</div>
|
|
|
|
</div>
|
|
|
|
<div className={styles.submissions}>
|
2024-07-30 10:28:57 +02:00
|
|
|
{sigits.map((sigit, index) => (
|
|
|
|
<DisplaySigit
|
|
|
|
key={`sigit-${index}`}
|
|
|
|
meta={sigit}
|
|
|
|
profiles={profiles}
|
|
|
|
setProfiles={setProfiles}
|
|
|
|
/>
|
|
|
|
))}
|
2024-08-06 12:42:21 +02:00
|
|
|
</div>
|
2024-07-30 10:28:57 +02:00
|
|
|
</Container>
|
2024-06-07 16:13:32 +05:00
|
|
|
)
|
|
|
|
}
|