diff --git a/apps/portal/package.json b/apps/portal/package.json index f135cab3..d57cdf43 100644 --- a/apps/portal/package.json +++ b/apps/portal/package.json @@ -27,6 +27,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "react-hook-form": "^7.36.1", + "react-pdf": "^5.7.2", "react-query": "^3.39.2", "superjson": "^1.10.0", "zod": "^3.18.0" @@ -37,6 +38,7 @@ "@types/node": "^18.0.0", "@types/react": "^18.0.21", "@types/react-dom": "^18.0.6", + "@types/react-pdf": "^5.7.2", "autoprefixer": "^10.4.12", "postcss": "^8.4.16", "prettier-plugin-tailwindcss": "^0.1.13", diff --git a/apps/portal/public/test_resume.pdf b/apps/portal/public/test_resume.pdf new file mode 100644 index 00000000..279b6a25 Binary files /dev/null and b/apps/portal/public/test_resume.pdf differ diff --git a/apps/portal/src/components/resumes/ResumePdf.tsx b/apps/portal/src/components/resumes/ResumePdf.tsx new file mode 100644 index 00000000..12debea4 --- /dev/null +++ b/apps/portal/src/components/resumes/ResumePdf.tsx @@ -0,0 +1,48 @@ +import { useState } from 'react'; +import { Document, Page, pdfjs } from 'react-pdf'; +import type { PDFDocumentProxy } from 'react-pdf/node_modules/pdfjs-dist'; +import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/20/solid'; +import { Button, Spinner } from '@tih/ui'; + +pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.js`; + +export default function ResumePdf() { + const [numPages, setNumPages] = useState(0); + const [pageNumber] = useState(1); + + const onPdfLoadSuccess = (pdf: PDFDocumentProxy) => { + setNumPages(pdf.numPages); + }; + + return ( +
+ } + onLoadSuccess={onPdfLoadSuccess}> + + + +
+
+
+ ); +} diff --git a/apps/portal/src/components/resumes/comments/CommentsForm.tsx b/apps/portal/src/components/resumes/comments/CommentsForm.tsx new file mode 100644 index 00000000..a20bfd0c --- /dev/null +++ b/apps/portal/src/components/resumes/comments/CommentsForm.tsx @@ -0,0 +1,149 @@ +import { useState } from 'react'; +import type { SubmitHandler } from 'react-hook-form'; +import { useForm } from 'react-hook-form'; +import { Button, Dialog, TextInput } from '@tih/ui'; + +type CommentsFormProps = Readonly<{ + setShowCommentsForm: (show: boolean) => void; +}>; + +type IFormInput = { + education: string; + experience: string; + general: string; + projects: string; + skills: string; +}; + +type InputKeys = keyof IFormInput; + +export default function CommentsForm({ + setShowCommentsForm, +}: CommentsFormProps) { + const [showDialog, setShowDialog] = useState(false); + const { + register, + handleSubmit, + setValue, + formState: { isDirty }, + } = useForm({ + defaultValues: { + education: '', + experience: '', + general: '', + projects: '', + skills: '', + }, + }); + + // TODO: Implement mutation to database + const onSubmit: SubmitHandler = (data) => { + alert(JSON.stringify(data)); + }; + + const onCancel = () => { + if (isDirty) { + setShowDialog(true); + } else { + setShowCommentsForm(false); + } + }; + + const onValueChange = (section: InputKeys, value: string) => { + setValue(section, value.trim(), { shouldDirty: true }); + }; + + return ( + <> +

Add your review

+ +
+ {/* TODO: Convert TextInput to TextArea */} +
+ onValueChange('general', value)} + /> + + onValueChange('education', value)} + /> + + onValueChange('experience', value)} + /> + + onValueChange('projects', value)} + /> + + onValueChange('skills', value)} + /> +
+ +
+
+
+ + setShowCommentsForm(false)} + /> + } + secondaryButton={ + + + ); +} diff --git a/apps/portal/src/components/resumes/comments/CommentsList.tsx b/apps/portal/src/components/resumes/comments/CommentsList.tsx new file mode 100644 index 00000000..397c9551 --- /dev/null +++ b/apps/portal/src/components/resumes/comments/CommentsList.tsx @@ -0,0 +1,32 @@ +import { useState } from 'react'; +import { Button, Tabs } from '@tih/ui'; + +import { COMMENTS_SECTIONS } from './constants'; + +type CommentsListProps = Readonly<{ + setShowCommentsForm: (show: boolean) => void; +}>; + +export default function CommentsList({ + setShowCommentsForm, +}: CommentsListProps) { + const [tab, setTab] = useState(COMMENTS_SECTIONS[0].value); + + return ( + <> + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+ + ); +} diff --git a/yarn.lock b/yarn.lock index baf467dc..8a87bd65 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3532,6 +3532,14 @@ dependencies: "@types/react" "*" +"@types/react-pdf@^5.7.2": + version "5.7.2" + resolved "https://registry.yarnpkg.com/@types/react-pdf/-/react-pdf-5.7.2.tgz#8e0ec89efeb4e574ec62b2370495bd3ee11d8ed8" + integrity sha512-6cUselXlQSNd9pMswJGvHqki3Lq0cnls/3hNwrFizdDeHBAfTFXTScEBObfGPznEmtO2LvmZMeced43BV9Wbog== + dependencies: + "@types/react" "*" + pdfjs-dist "^2.10.377" + "@types/react-router-config@*", "@types/react-router-config@^5.0.6": version "5.0.6" resolved "https://registry.yarnpkg.com/@types/react-router-config/-/react-router-config-5.0.6.tgz#87c5c57e72d241db900d9734512c50ccec062451" @@ -6381,6 +6389,11 @@ domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3: dependencies: domelementtype "^2.3.0" +dommatrix@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dommatrix/-/dommatrix-1.0.3.tgz#e7c18e8d6f3abdd1fef3dd4aa74c4d2e620a0525" + integrity sha512-l32Xp/TLgWb8ReqbVJAFIvXmY7go4nTxxlWiAFyhoQw9RKEOHBZNnyGvJWqDVSPmq3Y9HlM4npqF/T6VMOXhww== + domutils@^2.0.0, domutils@^2.5.2, domutils@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" @@ -7588,7 +7601,7 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -file-loader@^6.2.0: +file-loader@^6.0.0, file-loader@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== @@ -9772,6 +9785,11 @@ magic-string@^0.26.1: dependencies: sourcemap-codec "^1.4.8" +make-cancellable-promise@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/make-cancellable-promise/-/make-cancellable-promise-1.1.0.tgz#b4e9fcb31db3a27417e44f80cffa598ec9ac9f4e" + integrity sha512-X5Opjm2xcZsOLuJ+Bnhb4t5yfu4ehlA3OKEYLtqUchgVzL/QaqW373ZUVxVHKwvJ38cmYuR4rAHD2yUvAIkTPA== + make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -9792,6 +9810,11 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +make-event-props@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-event-props/-/make-event-props-1.3.0.tgz#2434cb390d58bcf40898d009ef5b1f936de9671b" + integrity sha512-oWiDZMcVB1/A487251hEWza1xzgCzl6MXxe9aF24l5Bt9N9UEbqTqKumEfuuLhmlhRZYnc+suVvW4vUs8bwO7Q== + makeerror@1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" @@ -9942,11 +9965,21 @@ meow@^3.1.0: redent "^1.0.0" trim-newlines "^1.0.0" +merge-class-names@^1.1.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/merge-class-names/-/merge-class-names-1.4.2.tgz#78d6d95ab259e7e647252a7988fd25a27d5a8835" + integrity sha512-bOl98VzwCGi25Gcn3xKxnR5p/WrhWFQB59MS/aGENcmUc6iSm96yrFDF0XSNurX9qN4LbJm0R9kfvsQ17i8zCw== + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== +merge-refs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/merge-refs/-/merge-refs-1.0.0.tgz#388348bce22e623782c6df9d3c4fc55888276120" + integrity sha512-WZ4S5wqD9FCR9hxkLgvcHJCBxzXzy3VVE6p8W2OzxRzB+hLRlcadGE2bW9xp2KSzk10rvp4y+pwwKO6JQVguMg== + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -11042,6 +11075,19 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" +pdfjs-dist@2.12.313: + version "2.12.313" + resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-2.12.313.tgz#62f2273737bb956267ae2e02cdfaddcb1099819c" + integrity sha512-1x6iXO4Qnv6Eb+YFdN5JdUzt4pAkxSp3aLAYPX93eQCyg/m7QFzXVWJHJVtoW48CI8HCXju4dSkhQZwoheL5mA== + +pdfjs-dist@^2.10.377: + version "2.16.105" + resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-2.16.105.tgz#937b9c4a918f03f3979c88209d84c1ce90122c2a" + integrity sha512-J4dn41spsAwUxCpEoVf6GVoz908IAA3mYiLmNxg8J9kfRXc2jxpbUepcP0ocp0alVNLFthTAM8DZ1RaHh8sU0A== + dependencies: + dommatrix "^1.0.3" + web-streams-polyfill "^3.2.1" + picocolors@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" @@ -12024,6 +12070,22 @@ react-loadable-ssr-addon-v5-slorber@^1.0.1: dependencies: "@babel/runtime" "^7.10.3" +react-pdf@^5.7.2: + version "5.7.2" + resolved "https://registry.yarnpkg.com/react-pdf/-/react-pdf-5.7.2.tgz#c458dedf7983822668b40dcac1eae052c1f6e056" + integrity sha512-hdDwvf007V0i2rPCqQVS1fa70CXut17SN3laJYlRHzuqcu8sLLjEoeXihty6c0Ev5g1mw31b8OT8EwRw1s8C4g== + dependencies: + "@babel/runtime" "^7.0.0" + file-loader "^6.0.0" + make-cancellable-promise "^1.0.0" + make-event-props "^1.1.0" + merge-class-names "^1.1.1" + merge-refs "^1.0.0" + pdfjs-dist "2.12.313" + prop-types "^15.6.2" + tiny-invariant "^1.0.0" + tiny-warning "^1.0.0" + react-query@^3.39.2: version "3.39.2" resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.39.2.tgz#9224140f0296f01e9664b78ed6e4f69a0cc9216f" @@ -13712,7 +13774,7 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" -tiny-invariant@^1.0.2: +tiny-invariant@^1.0.0, tiny-invariant@^1.0.2: version "1.3.1" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== @@ -14509,6 +14571,11 @@ web-namespaces@^1.0.0: resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec" integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw== +web-streams-polyfill@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" + integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"