Compare commits
2 Commits
83ddc1bbc8
...
15aa98e9db
Author | SHA1 | Date | |
---|---|---|---|
15aa98e9db | |||
93b2477839 |
@ -30,6 +30,7 @@
|
||||
border: 1px solid rgba(0, 0, 0, 0.137);
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
&.selected {
|
||||
@ -42,13 +43,13 @@
|
||||
border-color: #01aaad79;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pdfImageWrapper {
|
||||
position: relative;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
&.drawing {
|
||||
@ -94,7 +95,7 @@
|
||||
background-color: #fff;
|
||||
border: 1px solid rgb(160, 160, 160);
|
||||
border-radius: 50%;
|
||||
color: #E74C3C;
|
||||
color: #e74c3c;
|
||||
font-size: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Button, TextField } from '@mui/material'
|
||||
import JSZip from 'jszip'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
import { useAppSelector } from '../../hooks'
|
||||
import { appPrivateRoutes, appPublicRoutes } from '../../routes'
|
||||
@ -40,6 +40,15 @@ type Sort = (typeof SORT_BY)[number]['value']
|
||||
|
||||
export const HomePage = () => {
|
||||
const navigate = useNavigate()
|
||||
const [searchParams, setSearchParams] = useSearchParams()
|
||||
const q = searchParams.get('q') ?? ''
|
||||
|
||||
useEffect(() => {
|
||||
const searchInput = document.getElementById('q') as HTMLInputElement | null
|
||||
if (searchInput) {
|
||||
searchInput.value = q
|
||||
}
|
||||
}, [q])
|
||||
|
||||
const [sigits, setSigits] = useState<{ [key: string]: Meta }>({})
|
||||
const [parsedSigits, setParsedSigits] = useState<{
|
||||
@ -118,131 +127,143 @@ export const HomePage = () => {
|
||||
[navigate]
|
||||
)
|
||||
|
||||
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop })
|
||||
const { getRootProps, getInputProps, isDragActive, open } = useDropzone({
|
||||
onDrop,
|
||||
noClick: true
|
||||
})
|
||||
|
||||
const [search, setSearch] = useState('')
|
||||
const [filter, setFilter] = useState<Filter>('Show all')
|
||||
const [sort, setSort] = useState<Sort>('desc')
|
||||
|
||||
return (
|
||||
<Container className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<div className={styles.filters}>
|
||||
<Select
|
||||
name={'filter-select'}
|
||||
value={filter}
|
||||
setValue={setFilter}
|
||||
options={FILTERS.map((f) => {
|
||||
return {
|
||||
label: f,
|
||||
value: f
|
||||
}
|
||||
})}
|
||||
/>
|
||||
<Select
|
||||
name={'sort-select'}
|
||||
value={sort}
|
||||
setValue={setSort}
|
||||
options={SORT_BY.map((s) => {
|
||||
return { ...s }
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.actionButtons}>
|
||||
<form
|
||||
className={styles.search}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault()
|
||||
const searchInput = e.currentTarget.elements.namedItem(
|
||||
'q'
|
||||
) as HTMLInputElement
|
||||
setSearch(searchInput.value)
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
name="q"
|
||||
placeholder="Search"
|
||||
size="small"
|
||||
type="search"
|
||||
onChange={(e) => {
|
||||
// Handle the case when users click native search input's clear or x
|
||||
if (e.currentTarget.value === '') {
|
||||
setSearch(e.currentTarget.value)
|
||||
<div {...getRootProps()}>
|
||||
<Container className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<div className={styles.filters}>
|
||||
<Select
|
||||
name={'filter-select'}
|
||||
value={filter}
|
||||
setValue={setFilter}
|
||||
options={FILTERS.map((f) => {
|
||||
return {
|
||||
label: f,
|
||||
value: f
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
width: '100%',
|
||||
fontSize: '16px',
|
||||
borderTopLeftRadius: 'var(----mui-shape-borderRadius)',
|
||||
borderBottomLeftRadius: 'var(----mui-shape-borderRadius)',
|
||||
'& .MuiInputBase-root': {
|
||||
borderTopRightRadius: 0,
|
||||
borderBottomRightRadius: 0
|
||||
},
|
||||
'& .MuiInputBase-input': {
|
||||
padding: '7px 14px'
|
||||
},
|
||||
'& .MuiOutlinedInput-notchedOutline': {
|
||||
display: 'none'
|
||||
}
|
||||
}}
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
sx={{
|
||||
minWidth: '44px',
|
||||
padding: '11.5px 12px',
|
||||
borderTopLeftRadius: 0,
|
||||
borderBottomLeftRadius: 0
|
||||
<Select
|
||||
name={'sort-select'}
|
||||
value={sort}
|
||||
setValue={setSort}
|
||||
options={SORT_BY.map((s) => {
|
||||
return { ...s }
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.actionButtons}>
|
||||
<form
|
||||
className={styles.search}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault()
|
||||
const searchInput = e.currentTarget.elements.namedItem(
|
||||
'q'
|
||||
) as HTMLInputElement
|
||||
searchParams.set('q', searchInput.value)
|
||||
setSearchParams(searchParams)
|
||||
}}
|
||||
variant={'contained'}
|
||||
>
|
||||
<FontAwesomeIcon icon={faSearch} />
|
||||
</Button>
|
||||
</form>
|
||||
<TextField
|
||||
id="q"
|
||||
name="q"
|
||||
placeholder="Search"
|
||||
size="small"
|
||||
type="search"
|
||||
defaultValue={q}
|
||||
onChange={(e) => {
|
||||
// Handle the case when users click native search input's clear or x
|
||||
if (e.currentTarget.value === '') {
|
||||
searchParams.delete('q')
|
||||
setSearchParams(searchParams)
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
width: '100%',
|
||||
fontSize: '16px',
|
||||
borderTopLeftRadius: 'var(----mui-shape-borderRadius)',
|
||||
borderBottomLeftRadius: 'var(----mui-shape-borderRadius)',
|
||||
'& .MuiInputBase-root': {
|
||||
borderTopRightRadius: 0,
|
||||
borderBottomRightRadius: 0
|
||||
},
|
||||
'& .MuiInputBase-input': {
|
||||
padding: '7px 14px'
|
||||
},
|
||||
'& .MuiOutlinedInput-notchedOutline': {
|
||||
display: 'none'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
sx={{
|
||||
minWidth: '44px',
|
||||
padding: '11.5px 12px',
|
||||
borderTopLeftRadius: 0,
|
||||
borderBottomLeftRadius: 0
|
||||
}}
|
||||
variant={'contained'}
|
||||
aria-label="Submit Search"
|
||||
>
|
||||
<FontAwesomeIcon icon={faSearch} />
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.dropzone}>
|
||||
<div {...getRootProps()}>
|
||||
<input {...getInputProps()} />
|
||||
{isDragActive ? (
|
||||
<p>Drop the files here ...</p>
|
||||
) : (
|
||||
<p>Click or drag files to upload!</p>
|
||||
)}
|
||||
<div
|
||||
className={`${styles.dropzone} ${isDragActive ? styles.isDragActive : ''}`}
|
||||
onClick={open}
|
||||
>
|
||||
<div>
|
||||
<input {...getInputProps()} />
|
||||
{isDragActive ? (
|
||||
<p>Drop the files here ...</p>
|
||||
) : (
|
||||
<p>Click or drag files to upload!</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.submissions}>
|
||||
{Object.keys(parsedSigits)
|
||||
.filter((s) => {
|
||||
const { title, signedStatus } = parsedSigits[s]
|
||||
const isMatch = title?.toLowerCase().includes(search.toLowerCase())
|
||||
switch (filter) {
|
||||
case 'Completed':
|
||||
return signedStatus === SignedStatus.Complete && isMatch
|
||||
case 'In-progress':
|
||||
return signedStatus === SignedStatus.Partial && isMatch
|
||||
case 'Show all':
|
||||
return isMatch
|
||||
default:
|
||||
console.error('Filter case not handled.')
|
||||
}
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const x = parsedSigits[a].createdAt ?? 0
|
||||
const y = parsedSigits[b].createdAt ?? 0
|
||||
return sort === 'desc' ? y - x : x - y
|
||||
})
|
||||
.map((key) => (
|
||||
<DisplaySigit
|
||||
key={`sigit-${key}`}
|
||||
parsedMeta={parsedSigits[key]}
|
||||
meta={sigits[key]}
|
||||
profiles={profiles}
|
||||
setProfiles={setProfiles}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Container>
|
||||
<div className={styles.submissions}>
|
||||
{Object.keys(parsedSigits)
|
||||
.filter((s) => {
|
||||
const { title, signedStatus } = parsedSigits[s]
|
||||
const isMatch = title?.toLowerCase().includes(q.toLowerCase())
|
||||
switch (filter) {
|
||||
case 'Completed':
|
||||
return signedStatus === SignedStatus.Complete && isMatch
|
||||
case 'In-progress':
|
||||
return signedStatus === SignedStatus.Partial && isMatch
|
||||
case 'Show all':
|
||||
return isMatch
|
||||
default:
|
||||
console.error('Filter case not handled.')
|
||||
}
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const x = parsedSigits[a].createdAt ?? 0
|
||||
const y = parsedSigits[b].createdAt ?? 0
|
||||
return sort === 'desc' ? y - x : x - y
|
||||
})
|
||||
.map((key) => (
|
||||
<DisplaySigit
|
||||
key={`sigit-${key}`}
|
||||
parsedMeta={parsedSigits[key]}
|
||||
meta={sigits[key]}
|
||||
profiles={profiles}
|
||||
setProfiles={setProfiles}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -53,31 +53,35 @@
|
||||
}
|
||||
|
||||
.dropzone {
|
||||
position: relative;
|
||||
|
||||
font-size: 16px;
|
||||
background-color: $overlay-background-color;
|
||||
height: 250px;
|
||||
transition: padding ease 0.2s;
|
||||
padding: 15px;
|
||||
color: rgba(0, 0, 0, 0.25);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
padding: 10px;
|
||||
|
||||
> div {
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
transition: background-color ease 0.2s;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
transition:
|
||||
background-color ease 0.2s,
|
||||
inset ease 0.2s;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
color: rgba(0, 0, 0, 0.25);
|
||||
height: 100%;
|
||||
border-radius: 2px;
|
||||
border: dashed 3px rgba(0, 0, 0, 0.1);
|
||||
font-size: 16px;
|
||||
inset: 15px;
|
||||
}
|
||||
|
||||
&.isDragActive,
|
||||
&:hover {
|
||||
&::before {
|
||||
inset: 10px;
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user