validate csv file on the frontend

This commit is contained in:
Hongbo Wu
2023-08-14 13:10:17 +08:00
parent 9321dab04b
commit 41f43ed5e1
3 changed files with 108 additions and 19 deletions

View File

@ -38,6 +38,7 @@
"axios": "^1.2.0",
"color2k": "^2.0.0",
"cookie": "^0.5.0",
"csv-file-validator": "^2.1.0",
"dayjs": "^1.11.7",
"diff-match-patch": "^1.0.5",
"epubjs": "^0.3.93",

View File

@ -1,28 +1,18 @@
import { ChangeEvent, useCallback, useMemo, useState } from 'react'
import { Toaster } from 'react-hot-toast'
import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers'
import { applyStoredTheme } from '../../../lib/themeUpdater'
import {
Box,
HStack,
VStack,
} from '../../../components/elements/LayoutPrimitives'
import 'antd/dist/antd.compact.css'
import CSVFileValidator, { ValidatorConfig } from 'csv-file-validator'
import { ChangeEvent, useState } from 'react'
import { SyncLoader } from 'react-spinners'
import { Button } from '../../../components/elements/Button'
import { FormLabel } from '../../../components/elements/FormElements'
import { HStack, VStack } from '../../../components/elements/LayoutPrimitives'
import { StyledText } from '../../../components/elements/StyledText'
import { ProfileLayout } from '../../../components/templates/ProfileLayout'
import { theme } from '../../../components/tokens/stitches.config'
import {
uploadImportFileRequestMutation,
UploadImportFileType,
} from '../../../lib/networking/mutations/uploadImportFileMutation'
import { Button } from '../../../components/elements/Button'
import { FormLabel } from '../../../components/elements/FormElements'
import { Loader } from '../../../components/templates/SavingRequest'
import { SyncLoader } from 'react-spinners'
import { theme } from '../../../components/tokens/stitches.config'
import { applyStoredTheme } from '../../../lib/themeUpdater'
type UploadState = 'none' | 'uploading' | 'completed'
@ -34,6 +24,71 @@ export default function ImportUploader(): JSX.Element {
const [type, setType] = useState<UploadImportFileType>()
const [uploadState, setUploadState] = useState<UploadState>('none')
const isUrlValid = (url: string | number | boolean) => {
if (typeof url !== 'string') {
return false
}
try {
new URL(url)
return true
} catch (e) {
return false
}
}
const isStateValid = (state: string | number | boolean) => {
if (typeof state !== 'string') {
return false
}
const validStates = ['SUCCEEDED', 'ARCHIVED']
return validStates.includes(state.toUpperCase())
}
const csvConfig: ValidatorConfig = {
headers: [
{
name: 'url',
inputName: 'url',
required: true,
unique: true,
validate: function (url) {
return isUrlValid(url)
},
},
{
name: 'state',
inputName: 'state',
required: false,
optional: true,
validate: function (state) {
return isStateValid(state)
},
},
{
name: 'labels',
inputName: 'labels',
required: false,
optional: true,
isArray: true,
},
{
name: 'saved_at',
inputName: 'saved_at',
required: false,
optional: true,
},
{
name: 'published_at',
inputName: 'published_at',
required: false,
optional: true,
},
],
isHeaderNameOptional: true,
}
const onFinish = (values: unknown) => {
console.log(values)
}
@ -58,6 +113,23 @@ export default function ImportUploader(): JSX.Element {
setUploadState('uploading')
try {
if (type == UploadImportFileType.URL_LIST) {
// validate csv file
try {
const csvData = await CSVFileValidator(file, csvConfig)
if (csvData.inValidData.length > 0) {
setErrorMessage(csvData.inValidData[0].message)
setUploadState('none')
return
}
} catch (error) {
console.log(error)
setErrorMessage('Invalid CSV file.')
setUploadState('none')
return
}
}
const result = await uploadImportFileRequestMutation(type, 'text/csv')
if (result && result.uploadSignedUrl) {

View File

@ -12734,6 +12734,15 @@ csstype@^3.0.2, csstype@^3.0.4:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340"
integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==
csv-file-validator@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/csv-file-validator/-/csv-file-validator-2.1.0.tgz#fc83e1e05835d7f03d03f8cce6235938e4cef32e"
integrity sha512-SzBtdw0eZaCIJQYwCsD9uCK6pnbeArS3sJ036kbv56aAyQ7L2v0UmynWgFwclVIPSp74C6ZLd8kxgEHFnhq98w==
dependencies:
famulus "^2.2.3"
lodash "^4.17.21"
papaparse "^5.3.2"
csv-stringify@*, csv-stringify@^6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/csv-stringify/-/csv-stringify-6.4.0.tgz#6d006dca9194700e44f9fbc541bee8bbbd4f459c"
@ -14615,6 +14624,13 @@ extsprintf@^1.2.0:
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
famulus@^2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/famulus/-/famulus-2.2.3.tgz#b895c67930d0a0055257e2c1933ab9522dd694a5"
integrity sha512-tEh0NlWBtXSu1t/uY1eN7DQbXXcezPUp2/q25Scbc0h+Wivu9GHcdVnzlOqhD6hetpaj9CMhRm5InSQscM7FWQ==
dependencies:
lodash "^4.17.20"
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@ -22080,7 +22096,7 @@ pako@~1.0.2, pako@~1.0.5:
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
papaparse@^5.4.1:
papaparse@^5.3.2, papaparse@^5.4.1:
version "5.4.1"
resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.4.1.tgz#f45c0f871853578bd3a30f92d96fdcfb6ebea127"
integrity sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==