feat: add dropzone and multiple files support
All checks were successful
Open PR on Staging / audit_and_check (pull_request) Successful in 33s
All checks were successful
Open PR on Staging / audit_and_check (pull_request) Successful in 33s
This commit is contained in:
parent
276ad23e2c
commit
83ddc1bbc8
45
package-lock.json
generated
45
package-lock.json
generated
@ -37,6 +37,7 @@
|
|||||||
"react-dnd": "16.0.1",
|
"react-dnd": "16.0.1",
|
||||||
"react-dnd-html5-backend": "16.0.1",
|
"react-dnd-html5-backend": "16.0.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
"react-dropzone": "^14.2.3",
|
||||||
"react-redux": "9.1.0",
|
"react-redux": "9.1.0",
|
||||||
"react-router-dom": "6.22.1",
|
"react-router-dom": "6.22.1",
|
||||||
"react-toastify": "10.0.4",
|
"react-toastify": "10.0.4",
|
||||||
@ -2680,6 +2681,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||||
},
|
},
|
||||||
|
"node_modules/attr-accept": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz",
|
||||||
|
"integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
"version": "1.6.7",
|
"version": "1.6.7",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
|
||||||
@ -3857,6 +3867,24 @@
|
|||||||
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||||
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/file-selector": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/file-selector/node_modules/tslib": {
|
||||||
|
"version": "2.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
|
||||||
|
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
|
||||||
|
"license": "0BSD"
|
||||||
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
@ -5716,6 +5744,23 @@
|
|||||||
"react": "^18.2.0"
|
"react": "^18.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-dropzone": {
|
||||||
|
"version": "14.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.3.tgz",
|
||||||
|
"integrity": "sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"attr-accept": "^2.2.2",
|
||||||
|
"file-selector": "^0.6.0",
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.13"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">= 16.8 || 18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "18.2.0",
|
"version": "18.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 32",
|
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 29",
|
||||||
"lint:fix": "eslint . --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
"lint:fix": "eslint . --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||||
"lint:staged": "eslint --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
"lint:staged": "eslint --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||||
"formatter:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"",
|
"formatter:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"",
|
||||||
@ -47,6 +47,7 @@
|
|||||||
"react-dnd": "16.0.1",
|
"react-dnd": "16.0.1",
|
||||||
"react-dnd-html5-backend": "16.0.1",
|
"react-dnd-html5-backend": "16.0.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
"react-dropzone": "^14.2.3",
|
||||||
"react-redux": "9.1.0",
|
"react-redux": "9.1.0",
|
||||||
"react-router-dom": "6.22.1",
|
"react-router-dom": "6.22.1",
|
||||||
"react-toastify": "10.0.4",
|
"react-toastify": "10.0.4",
|
||||||
|
@ -24,7 +24,7 @@ import JSZip from 'jszip'
|
|||||||
import { MuiFileInput } from 'mui-file-input'
|
import { MuiFileInput } from 'mui-file-input'
|
||||||
import { Event, kinds } from 'nostr-tools'
|
import { Event, kinds } from 'nostr-tools'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { DndProvider, DragSourceMonitor, useDrag, useDrop } from 'react-dnd'
|
import { DndProvider, useDrag, useDrop } from 'react-dnd'
|
||||||
import { HTML5Backend } from 'react-dnd-html5-backend'
|
import { HTML5Backend } from 'react-dnd-html5-backend'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
@ -68,7 +68,7 @@ import { Mark } from '../../types/mark.ts'
|
|||||||
export const CreatePage = () => {
|
export const CreatePage = () => {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const { uploadedFile } = location.state || {}
|
const { uploadedFiles } = location.state || {}
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [loadingSpinnerDesc, setLoadingSpinnerDesc] = useState('')
|
const [loadingSpinnerDesc, setLoadingSpinnerDesc] = useState('')
|
||||||
@ -134,10 +134,10 @@ export const CreatePage = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (uploadedFile) {
|
if (uploadedFiles) {
|
||||||
setSelectedFiles([uploadedFile])
|
setSelectedFiles([...uploadedFiles])
|
||||||
}
|
}
|
||||||
}, [uploadedFile])
|
}, [uploadedFiles])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (usersPubkey) {
|
if (usersPubkey) {
|
||||||
@ -979,7 +979,7 @@ const SignerRow = ({
|
|||||||
item: () => {
|
item: () => {
|
||||||
return { id: user.pubkey, index }
|
return { id: user.pubkey, index }
|
||||||
},
|
},
|
||||||
collect: (monitor: DragSourceMonitor) => ({
|
collect: (monitor) => ({
|
||||||
isDragging: monitor.isDragging()
|
isDragging: monitor.isDragging()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Button, TextField } from '@mui/material'
|
import { Button, TextField } from '@mui/material'
|
||||||
import JSZip from 'jszip'
|
import JSZip from 'jszip'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import { useAppSelector } from '../../hooks'
|
import { useAppSelector } from '../../hooks'
|
||||||
@ -10,7 +10,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|||||||
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { Select } from '../../components/Select'
|
import { Select } from '../../components/Select'
|
||||||
import { DisplaySigit } from '../../components/DisplaySigit'
|
import { DisplaySigit } from '../../components/DisplaySigit'
|
||||||
|
import { useDropzone } from 'react-dropzone'
|
||||||
import { Container } from '../../components/Container'
|
import { Container } from '../../components/Container'
|
||||||
import styles from './style.module.scss'
|
import styles from './style.module.scss'
|
||||||
import {
|
import {
|
||||||
@ -24,8 +24,8 @@ const FILTERS = [
|
|||||||
'Show all',
|
'Show all',
|
||||||
// 'Drafts',
|
// 'Drafts',
|
||||||
'In-progress',
|
'In-progress',
|
||||||
'Completed',
|
'Completed'
|
||||||
'Archived'
|
// 'Archived'
|
||||||
] as const
|
] as const
|
||||||
type Filter = (typeof FILTERS)[number]
|
type Filter = (typeof FILTERS)[number]
|
||||||
|
|
||||||
@ -40,7 +40,6 @@ type Sort = (typeof SORT_BY)[number]['value']
|
|||||||
|
|
||||||
export const HomePage = () => {
|
export const HomePage = () => {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
|
||||||
|
|
||||||
const [sigits, setSigits] = useState<{ [key: string]: Meta }>({})
|
const [sigits, setSigits] = useState<{ [key: string]: Meta }>({})
|
||||||
const [parsedSigits, setParsedSigits] = useState<{
|
const [parsedSigits, setParsedSigits] = useState<{
|
||||||
@ -74,51 +73,52 @@ export const HomePage = () => {
|
|||||||
}
|
}
|
||||||
}, [usersAppData])
|
}, [usersAppData])
|
||||||
|
|
||||||
const handleUploadClick = () => {
|
const onDrop = useCallback(
|
||||||
if (fileInputRef.current) {
|
async (acceptedFiles: File[]) => {
|
||||||
fileInputRef.current.click()
|
// When uploading single file check if it's .sigit.zip
|
||||||
}
|
if (acceptedFiles.length === 1) {
|
||||||
}
|
const file = acceptedFiles[0]
|
||||||
|
|
||||||
const handleFileChange = async (
|
// Check if the file extension is .sigit.zip
|
||||||
event: React.ChangeEvent<HTMLInputElement>
|
const fileName = file.name
|
||||||
) => {
|
const fileExtension = fileName.slice(-10) // ".sigit.zip" has 10 characters
|
||||||
const file = event.target.files?.[0]
|
if (fileExtension === '.sigit.zip') {
|
||||||
if (file) {
|
const zip = await JSZip.loadAsync(file).catch((err) => {
|
||||||
// Check if the file extension is .sigit.zip
|
console.log('err in loading zip file :>> ', err)
|
||||||
const fileName = file.name
|
toast.error(err.message || 'An error occurred in loading zip file.')
|
||||||
const fileExtension = fileName.slice(-10) // ".sigit.zip" has 10 characters
|
return null
|
||||||
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 (!zip) return
|
||||||
if ('meta.json' in zip.files) {
|
|
||||||
return navigate(appPublicRoutes.verify, {
|
|
||||||
state: { uploadedZip: file }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
toast.error('Invalid zip file')
|
// navigate to sign page if zip contains keys.json
|
||||||
return
|
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 SiGit zip file')
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// navigate to create page
|
// navigate to create page
|
||||||
navigate(appPrivateRoutes.create, { state: { uploadedFile: file } })
|
navigate(appPrivateRoutes.create, {
|
||||||
}
|
state: { uploadedFiles: acceptedFiles }
|
||||||
}
|
})
|
||||||
|
},
|
||||||
|
[navigate]
|
||||||
|
)
|
||||||
|
|
||||||
|
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop })
|
||||||
|
|
||||||
const [search, setSearch] = useState('')
|
const [search, setSearch] = useState('')
|
||||||
const [filter, setFilter] = useState<Filter>('Show all')
|
const [filter, setFilter] = useState<Filter>('Show all')
|
||||||
@ -202,15 +202,15 @@ export const HomePage = () => {
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.dropzone} onClick={handleUploadClick}>
|
<div className={styles.dropzone}>
|
||||||
<input
|
<div {...getRootProps()}>
|
||||||
id="fileUpload"
|
<input {...getInputProps()} />
|
||||||
type="file"
|
{isDragActive ? (
|
||||||
hidden
|
<p>Drop the files here ...</p>
|
||||||
ref={fileInputRef}
|
) : (
|
||||||
onChange={handleFileChange}
|
<p>Click or drag files to upload!</p>
|
||||||
/>
|
)}
|
||||||
<div>Click or drag files to upload!</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.submissions}>
|
<div className={styles.submissions}>
|
||||||
{Object.keys(parsedSigits)
|
{Object.keys(parsedSigits)
|
||||||
|
@ -120,6 +120,7 @@ export const queryNip05 = async (
|
|||||||
if (!match) throw new Error('Invalid nip05')
|
if (!match) throw new Error('Invalid nip05')
|
||||||
|
|
||||||
// Destructure the match result, assigning default value '_' to name if not provided
|
// Destructure the match result, assigning default value '_' to name if not provided
|
||||||
|
// First variable from the match destructuring is ignored
|
||||||
const [, name = '_', domain] = match
|
const [, name = '_', domain] = match
|
||||||
|
|
||||||
// Construct the URL to query the NIP-05 data
|
// Construct the URL to query the NIP-05 data
|
||||||
|
Loading…
Reference in New Issue
Block a user