Skip to content

Commit

Permalink
add pdf uploader
Browse files Browse the repository at this point in the history
  • Loading branch information
tripluyi committed Jun 2, 2023
1 parent a60b8f1 commit e6c801e
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 8 deletions.
24 changes: 16 additions & 8 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
webpack(config) {
config.experiments = {
asyncWebAssembly: true,
layers: true,
};
reactStrictMode: true,
webpack: (config, options) => {
config.experiments = {
asyncWebAssembly: true,
layers: true,
}

return config;
},
// config.module.rules.push({
// test: /pdf\.js$/,
// loader: 'babel-loader',
// options: {
// presets: ['@babel/preset-env'],
// plugins: ['@babel/plugin-proposal-private-property-in-object'],
// },
// })
return config
},
}

module.exports = nextConfig
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"check-types": "tsc --noemit",
"eslint:commit": "git diff --cached --name-only | grep -E 'src.*\\.[jt]sx?$' | xargs ./node_modules/.bin/eslint --quiet",
"eslint:quiet": "./node_modules/.bin/eslint \"src/**/*.{js,jsx,ts,tsx}\" --ignore-pattern \"src/lib/\" --ignore-pattern \"src/shared/\" --quiet",
"prettier:single": "./node_modules/.bin/prettier --single-quote --no-semi --trailing-comma es5 --print-width 120 --tab-width 4 --arrow-parens avoid --write",
"prettier": "./node_modules/.bin/prettier --single-quote --no-semi --trailing-comma es5 --print-width 120 --tab-width 4 --arrow-parens avoid --write \"src/**/*.{js,jsx,ts,tsx}\"",
"prettier:check": "npm run prettier -- --list-different",
"lint-staged": "lint-staged"
Expand Down Expand Up @@ -45,6 +46,7 @@
"react": "18.2.0",
"react-dom": "18.2.0",
"react-markdown": "^8.0.7",
"react-pdf": "^7.0.3",
"react-redux": "^8.0.5",
"redis": "^4.6.6",
"redux-devtools-extension": "^2.13.9",
Expand All @@ -57,6 +59,7 @@
"@types/lodash": "^4.14.192",
"@typescript-eslint/eslint-plugin": "^5.59.5",
"@typescript-eslint/parser": "^5.59.5",
"babel-loader": "^9.1.2",
"eslint": "^8.40.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-flowtype": "^8.0.3",
Expand All @@ -66,6 +69,7 @@
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"lint-staged": "^13.2.2",
"pdf-loader": "^1.0.2",
"pre-commit": "^1.2.2",
"prettier": "^2.8.8"
}
Expand Down
100 changes: 100 additions & 0 deletions src/modules/pdfReader/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import React, { useEffect, useState, useCallback } from 'react'
import _ from 'lodash'
import { Document, Page, pdfjs } from 'react-pdf' //'react-pdf';

// 设置 PDF.js 的 workerSrc
pdfjs.GlobalWorkerOptions.workerSrc = '/api/pdf.worker'

const PdfReader = () => {
const [file, setFile] = useState(null)
const [fileLoadStatus, setFileLoadStatus] = useState(0)

const onFileChange = event => {
setFileLoadStatus(0)
const newFile = event?.target?.files[0]
if (newFile) setFile(newFile)
}

const onLoadedSuccess = () => {
setFileLoadStatus(1)
}
return (
<div id={`pdfreader`}>
<div className="top_line"></div>
<FileUploader onChange={onFileChange} />
{file ? <ControlledCarousel file={file} loadCallback={onLoadedSuccess} /> : null}
</div>
)
}

export default PdfReader

const FileUploader = (props: { onChange: (arg: any) => void }) => {
const { onChange } = props || {}
return (
<div className="m-5 w-96">
<label
className="block ml-1 mb-2 text-sm font-medium text-gray-900 dark:text-white cursor-pointer"
htmlFor="pdf_uploader_input"
>
Choose PDF
</label>
<input
className="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400"
aria-describedby="user_avatar_help"
id="pdf_uploader_input"
type="file"
onChange={onChange}
/>
</div>
)
}
const ControlledCarousel = ({ file, loadCallback }: { file: any; loadCallback?: (arg?: any) => void }) => {
const [index, setIndex] = useState(0)
const [numPages, setNumPages] = useState(null)

const handleSelect = (selectedIndex, e) => {
setIndex(selectedIndex)
}

const onDocumentLoadSuccess = documentArgs => {
console.log(documentArgs)
const { numPages } = documentArgs || {}
setNumPages(numPages)
if (typeof loadCallback == `function`) {
loadCallback()
}
}

let temp: any = []
const onPageTextLoadSuccess = page => {
page.getTextContent().then(textContent => {
temp.push({
page: page.pageNumber,
contentList: textContent?.items,
})
})
}

return (
<div>
<Document file={file} onLoadSuccess={onDocumentLoadSuccess}>
{_.map(new Array(numPages), (el, index) => (
<div className="inside_carousel" key={`pdf_page_${index}`}>
<Page
key={`page_${index + 1}`}
pageNumber={index + 1}
renderTextLayer={false}
renderAnnotationLayer={false}
onLoadSuccess={page => onPageTextLoadSuccess(page)}
/>
<p className="pdf_page_number">
Page {index + 1} of {numPages}
</p>
<br />
</div>
))}
</Document>
</div>
)
}
25 changes: 25 additions & 0 deletions src/pages/api/pdf.worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { NextApiRequest, NextApiResponse } from 'next'
import fs from 'fs'
import path from 'path'
import { findSpecificDir } from '@/utils/serverUtil'

const PdfWorker = async (req: NextApiRequest, res: NextApiResponse) => {
const rootDir = await findSpecificDir({ startPath: __dirname, specificFile: 'readme.md' })
const pdfworkerjs = path.resolve(rootDir, './node_modules/pdfjs-dist/build/pdf.worker.js')
console.log(`pdfworkerjs`, pdfworkerjs)
console.log(`this is /pdf.worker.js`)
fs.readFile(pdfworkerjs, (err, data) => {
if (err) {
console.log(`fs error`, err)
res.setHeader('Content-Type', 'text/plain')
res.status(404)
res.end('404 Not Found\n')
return
}
res.setHeader('Content-Type', 'application/javascript')
res.write(data)
res.end()
})
}

export default PdfWorker
2 changes: 2 additions & 0 deletions src/pages/candidateHunting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import type { NextPage, GetServerSideProps } from 'next'
import { useEffect } from 'react'
import HeaderModule from '@/modules/header'
import { navigationEnum } from '@/utils/constants'
import PdfReader from '@/modules/pdfReader'

const CandidateHunting: NextPage<{ serverSideData: any }, any> = ({ serverSideData }: { serverSideData: any }) => {
return (
<div>
<HeaderModule current={navigationEnum.candidateHunting} />
<PdfReader />
</div>
)
}
Expand Down
19 changes: 19 additions & 0 deletions src/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,22 @@ body {
)
rgb(var(--background-start-rgb));
}

input[type=file]::file-selector-button:hover {
background: unset;
@apply bg-gray-600;
}
input[type=file]::-webkit-file-upload-button,
input[type=file]::file-selector-button {
margin-inline-start: -1rem;
margin-inline-end: 1rem;

border-color: inherit;
border-radius: 0;
border-width: 0;
font-size: unset;
line-height: inherit;
padding: 0;
@apply text-white bg-gray-700 font-medium text-sm cursor-pointer border-0 py-2.5 pl-8 pr-4;
}

44 changes: 44 additions & 0 deletions src/utils/serverUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import _ from 'lodash'
import fs from 'fs'
import path from 'path'

export const sleep = async (sec?: number): Promise<void> => {
const secNumber = Number(sec) || 1
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, secNumber * 1000)
})
}

export const findSpecificDir = async ({
startPath,
excludeDir,
specificFile,
}: {
specificFile: string
startPath?: string
excludeDir?: string
}): Promise<string> => {
let currentPath = startPath || __dirname

while (currentPath !== '/') {
if (excludeDir && path.basename(currentPath) === excludeDir) {
// Skip the "publish" folder and continue searching
currentPath = path.dirname(currentPath)
continue
}

const specificFilePath = path.join(currentPath, specificFile)
try {
await fs.promises.access(specificFilePath)
return currentPath
} catch (e) {
// Ignore error and continue searching
}

currentPath = path.dirname(currentPath)
}

throw new Error(`Could not find package.json folder starting from ${startPath}`)
}

0 comments on commit e6c801e

Please sign in to comment.