├── .all-contributorsrc
├── .editorconfig
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── dependabot.yml
├── .gitignore
├── .prettierrc
├── LICENSE
├── README.md
├── package.json
├── public
├── android-chrome-192x192.png
├── android-chrome-512x512.png
├── apple-touch-icon.png
├── certificate-logo.png
├── data.json
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon.ico
├── index.html
├── manifest.json
└── robots.txt
├── src
├── App.js
├── App.module.scss
├── App.test.js
├── assets
│ ├── club.jpg
│ └── logo.jpg
├── components
│ ├── Certificate.jsx
│ ├── Footer.jsx
│ ├── Generate.jsx
│ ├── Home.jsx
│ ├── Login.jsx
│ ├── Navigation.jsx
│ ├── Verify.jsx
│ └── index.js
├── css
│ ├── FrontCertificate.module.css
│ ├── Login.module.css
│ └── Verify.module.css
├── index.css
├── index.js
├── reportWebVitals.js
└── setupTests.js
└── yarn.lock
/.all-contributorsrc:
--------------------------------------------------------------------------------
1 | {
2 | "projectName": "Certificate Verification and Generation System for IIITV",
3 | "projectOwner": "Pushkar Patel ",
4 | "repoType": "github",
5 | "repoHost": "https://github.com",
6 | "files": [
7 | "README.md"
8 | ],
9 | "imageSize": 100,
10 | "commit": false,
11 | "commitConvention": "none",
12 | "contributors": [
13 | {
14 | "login": "TanmayAmbadkar",
15 | "name": "Tanmay Ambadkar",
16 | "avatar_url": "https://avatars.githubusercontent.com/u/42721553?v=4",
17 | "profile": "https://github.com/TanmayAmbadkar",
18 | "contributions": [
19 | "code",
20 | "ideas",
21 | "projectManagement"
22 | ]
23 | },
24 | {
25 | "login": "thepushkarp",
26 | "name": "Pushkar Patel",
27 | "avatar_url": "https://avatars.githubusercontent.com/u/42088801?v=4",
28 | "profile": "https://github.com/thepushkarp",
29 | "contributions": [
30 | "code",
31 | "design",
32 | "doc"
33 | ]
34 | },
35 | {
36 | "login": "pAditya198",
37 | "name": "Aditya Prakash",
38 | "avatar_url": "https://avatars.githubusercontent.com/u/42460356?v=4",
39 | "profile": "https://github.com/pAditya198",
40 | "contributions": [
41 | "code",
42 | "bug",
43 | "design"
44 | ]
45 | },
46 | {
47 | "login": "anujpuri72",
48 | "name": "Anuj Puri",
49 | "avatar_url": "https://avatars.githubusercontent.com/u/42184782?v=4",
50 | "profile": "https://github.com/anujpuri72",
51 | "contributions": [
52 | "code",
53 | "bug",
54 | "userTesting"
55 | ]
56 | },
57 | {
58 | "login": "thecodepapaya",
59 | "name": "Ashutosh Singh",
60 | "avatar_url": "https://avatars.githubusercontent.com/u/42690541?v=4",
61 | "profile": "https://github.com/thecodepapaya",
62 | "contributions": [
63 | "ideas",
64 | "userTesting",
65 | "projectManagement"
66 | ]
67 | }
68 | ],
69 | "contributorsPerLine": 7
70 | }
71 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # top-most EditorConfig file
2 | root = true
3 |
4 | # Unix-style newlines with a newline ending every file
5 | [*]
6 | charset = utf-8
7 | insert_final_newline = true
8 | trim_trailing_whitespace = true
9 | end_of_line = lf
10 |
11 | # 4 space indentation
12 | indent_style = space
13 | indent_size = 2
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: npm
9 | directory: "/"
10 | schedule:
11 | interval: monthly
12 | time: "08:30"
13 | timezone: Asia/Kolkata
14 | open-pull-requests-limit: 10
15 |
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 | package-lock.json
25 |
26 | # CSS Modules
27 | !*.modules.css
28 | !*.module.scss
29 | !*.module.sass
30 |
31 | .eslintcache
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 85,
3 | "arrowParens": "always",
4 | "semi": true,
5 | "tabWidth": 2,
6 | "singleQuote": true,
7 | "trailingComma": "es5",
8 | "bracketSpacing": true
9 | }
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Pushkar Patel
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | Certificate Verification and Generation System for IIITV
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | E-certificate verification and generation system for Indian Institute of Information Technology Vadodara built using React, Bootstrap and HTML5 Canvas
14 |
15 | ---
16 |
17 | This system is deployed at [https://mycertificatesgymkhana.iiitvadodara.ac.in/](https://mycertificatesgymkhana.iiitvadodara.ac.in/). The backend can be found at [CertificateGenerator](https://github.com/TanmayAmbadkar/CertificateGenerator).
18 |
19 | ## How to use?
20 |
21 | - Go to [https://mycertificatesgymkhana.iiitvadodara.ac.in/](https://mycertificatesgymkhana.iiitvadodara.ac.in/)
22 | - Click on the `Verify` button
23 | - Enter your Roll number in the input box
24 | - If certificates do not exist for your roll number, you'll get a message telling that this ID does not exists.
25 | - If certificates exist, you'll get a list of certificates, with their IDs.
26 | - Click on a certificate ID to view the certificate and download it.
27 | - Show off your certificate to everyone!
28 |
29 | ## Found a bug? Want to suggest improvements?
30 |
31 | Feel free to [Open an issue](https://github.com/thepushkarp/certificate-generator-frontend/issues/new/choose) in case you found a bug or want to suggest improvements.
32 |
33 | ## Contributors
34 |
35 |
36 |
37 |
38 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "certificate-generator-frontend",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^6.4.2",
7 | "@testing-library/react": "^12.1.4",
8 | "@testing-library/user-event": "^13.5.0",
9 | "bootstrap": "^4.5.3",
10 | "clsx": "^1.1.1",
11 | "file-saver": "^2.0.5",
12 | "jspdf": "^2.5.1",
13 | "jszip": "^3.5.0",
14 | "node-sass": "^7.0.1",
15 | "react": "^17.0.1",
16 | "react-bootstrap": "^1.4.0",
17 | "react-dom": "^17.0.1",
18 | "react-router-bootstrap": "^0.26.2",
19 | "react-router-dom": "^5.2.0",
20 | "react-scripts": "4.0.1",
21 | "web-vitals": "^2.1.4"
22 | },
23 | "scripts": {
24 | "start": "react-scripts start",
25 | "build": "react-scripts build",
26 | "test": "react-scripts test",
27 | "eject": "react-scripts eject",
28 | "format": "prettier --write \"**/*.+(js|jsx|json|css|scss|sass|md)\"",
29 | "contributors:add": "all-contributors add",
30 | "contributors:generate": "all-contributors generate"
31 | },
32 | "eslintConfig": {
33 | "extends": [
34 | "react-app",
35 | "react-app/jest"
36 | ]
37 | },
38 | "browserslist": {
39 | "production": [
40 | ">0.2%",
41 | "not dead",
42 | "not op_mini all"
43 | ],
44 | "development": [
45 | "last 1 chrome version",
46 | "last 1 firefox version",
47 | "last 1 safari version"
48 | ]
49 | },
50 | "husky": {
51 | "hooks": {
52 | "pre-commit": "lint-staged"
53 | }
54 | },
55 | "lint-staged": {
56 | "*.+(js|jsx|json|css|scss|sass|md)": [
57 | "prettier --write"
58 | ]
59 | },
60 | "devDependencies": {
61 | "all-contributors-cli": "^6.26.1",
62 | "husky": "^9.0.10",
63 | "lint-staged": "^15.2.2",
64 | "prettier": "^3.2.5"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thepushkarp/certificate-generator-frontend/5024ac1c6c139da1c8f0226130d6afcab807643e/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thepushkarp/certificate-generator-frontend/5024ac1c6c139da1c8f0226130d6afcab807643e/public/android-chrome-512x512.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thepushkarp/certificate-generator-frontend/5024ac1c6c139da1c8f0226130d6afcab807643e/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/certificate-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thepushkarp/certificate-generator-frontend/5024ac1c6c139da1c8f0226130d6afcab807643e/public/certificate-logo.png
--------------------------------------------------------------------------------
/public/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "IIITV/STUD-GYMKHANA/CERT/456/000028": {
3 | "Name": "Aman Sagar",
4 | "Sub Event Name": "Zest Up",
5 | "Position": "1st",
6 | "Academic Year": "2019-2020",
7 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000028",
8 | "Date": "27-01-2021",
9 | "RollNo": 201851016,
10 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-28.pdf",
11 | "Email": "201851018@iiitvadodara.ac.in"
12 | },
13 | "IIITV/STUD-GYMKHANA/CERT/456/000029": {
14 | "Name": "Palak Ambade",
15 | "Sub Event Name": "Synergy",
16 | "Position": "1st",
17 | "Academic Year": "2019-2020",
18 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000029",
19 | "Date": "27-01-2021",
20 | "RollNo": 201751029,
21 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-29.pdf",
22 | "Email": "201851018@iiitvadodara.ac.in"
23 | },
24 | "IIITV/STUD-GYMKHANA/CERT/456/000030": {
25 | "Name": "Anagha Mittal",
26 | "Sub Event Name": "Synergy",
27 | "Position": "1st",
28 | "Academic Year": "2019-2020",
29 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000030",
30 | "Date": "27-01-2021",
31 | "RollNo": 201851020,
32 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-30.pdf",
33 | "Email": "201851018@iiitvadodara.ac.in"
34 | },
35 | "IIITV/STUD-GYMKHANA/CERT/456/000031": {
36 | "Name": "Varnika Dasgupta",
37 | "Sub Event Name": "Synergy",
38 | "Position": "1st",
39 | "Academic Year": "2019-2020",
40 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000031",
41 | "Date": "27-01-2021",
42 | "RollNo": 201751060,
43 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-31.pdf",
44 | "Email": "201851018@iiitvadodara.ac.in"
45 | },
46 | "IIITV/STUD-GYMKHANA/CERT/456/000032": {
47 | "Name": "Prachi Desai",
48 | "Sub Event Name": "Synergy",
49 | "Position": "1st",
50 | "Academic Year": "2019-2020",
51 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000032",
52 | "Date": "27-01-2021",
53 | "RollNo": 201852024,
54 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-32.pdf",
55 | "Email": "201851018@iiitvadodara.ac.in"
56 | },
57 | "IIITV/STUD-GYMKHANA/CERT/456/000033": {
58 | "Name": "Swasti Khurana",
59 | "Sub Event Name": "Synergy",
60 | "Position": "1st",
61 | "Academic Year": "2019-2020",
62 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000033",
63 | "Date": "27-01-2021",
64 | "RollNo": 201852030,
65 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-33.pdf",
66 | "Email": "201851018@iiitvadodara.ac.in"
67 | },
68 | "IIITV/STUD-GYMKHANA/CERT/456/000034": {
69 | "Name": "Parul Soni",
70 | "Sub Event Name": "Synergy",
71 | "Position": "1st",
72 | "Academic Year": "2019-2020",
73 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000034",
74 | "Date": "27-01-2021",
75 | "RollNo": 201651036,
76 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-34.pdf",
77 | "Email": "201851018@iiitvadodara.ac.in"
78 | },
79 | "IIITV/STUD-GYMKHANA/CERT/456/000035": {
80 | "Name": "Monika Phandnis",
81 | "Sub Event Name": "Synergy",
82 | "Position": "1st",
83 | "Academic Year": "2019-2020",
84 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000035",
85 | "Date": "27-01-2021",
86 | "RollNo": 201651032,
87 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-35.pdf",
88 | "Email": "201851018@iiitvadodara.ac.in"
89 | },
90 | "IIITV/STUD-GYMKHANA/CERT/456/000036": {
91 | "Name": "Shivanshi Dave",
92 | "Sub Event Name": "Synergy",
93 | "Position": "1st",
94 | "Academic Year": "2019-2020",
95 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000036",
96 | "Date": "27-01-2021",
97 | "RollNo": 201851036,
98 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-36.pdf",
99 | "Email": "201851018@iiitvadodara.ac.in"
100 | },
101 | "IIITV/STUD-GYMKHANA/CERT/456/000037": {
102 | "Name": "Vaidehi Vaishnav",
103 | "Sub Event Name": "Nishad",
104 | "Position": "1st",
105 | "Academic Year": "2019-2020",
106 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000037",
107 | "Date": "27-01-2021",
108 | "RollNo": 201751059,
109 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-37.pdf",
110 | "Email": "201851018@iiitvadodara.ac.in"
111 | },
112 | "IIITV/STUD-GYMKHANA/CERT/456/000038": {
113 | "Name": "Anshuman Singh",
114 | "Sub Event Name": "Crescendo",
115 | "Position": "1st",
116 | "Academic Year": "2019-2020",
117 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000038",
118 | "Date": "27-01-2021",
119 | "RollNo": 201951026,
120 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-38.pdf",
121 | "Email": "201851018@iiitvadodara.ac.in"
122 | },
123 | "IIITV/STUD-GYMKHANA/CERT/456/000039": {
124 | "Name": "Deepanshu Singh",
125 | "Sub Event Name": "Nazara",
126 | "Position": "1st",
127 | "Academic Year": "2019-2020",
128 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000039",
129 | "Date": "27-01-2021",
130 | "RollNo": 201951054,
131 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-39.pdf",
132 | "Email": "201851018@iiitvadodara.ac.in"
133 | },
134 | "IIITV/STUD-GYMKHANA/CERT/456/000040": {
135 | "Name": "Akshita Agrawalla",
136 | "Sub Event Name": "Abhinay",
137 | "Position": "1st",
138 | "Academic Year": "2019-2020",
139 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000040",
140 | "Date": "27-01-2021",
141 | "RollNo": 201751066,
142 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-40.pdf",
143 | "Email": "201851018@iiitvadodara.ac.in"
144 | },
145 | "IIITV/STUD-GYMKHANA/CERT/456/000041": {
146 | "Name": "Ashutosh Kushwaha",
147 | "Sub Event Name": "Dvandva",
148 | "Position": "1st",
149 | "Academic Year": "2019-2020",
150 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000041",
151 | "Date": "27-01-2021",
152 | "RollNo": 201651009,
153 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-41.pdf",
154 | "Email": "201851018@iiitvadodara.ac.in"
155 | },
156 | "IIITV/STUD-GYMKHANA/CERT/456/000042": {
157 | "Name": "Mansi Gupta",
158 | "Sub Event Name": "Dvandva",
159 | "Position": "1st",
160 | "Academic Year": "2019-2020",
161 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000042",
162 | "Date": "27-01-2021",
163 | "RollNo": 201852019,
164 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-42.pdf",
165 | "Email": "201851018@iiitvadodara.ac.in"
166 | },
167 | "IIITV/STUD-GYMKHANA/CERT/456/000043": {
168 | "Name": "Adit Alware",
169 | "Sub Event Name": "Kroodle",
170 | "Position": "1st",
171 | "Academic Year": "2019-2020",
172 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000043",
173 | "Date": "27-01-2021",
174 | "RollNo": 201851006,
175 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-43.pdf",
176 | "Email": "201851018@iiitvadodara.ac.in"
177 | },
178 | "IIITV/STUD-GYMKHANA/CERT/456/000044": {
179 | "Name": "Keshav Purohit",
180 | "Sub Event Name": "Mystery Box",
181 | "Position": "1st",
182 | "Academic Year": "2019-2020",
183 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000044",
184 | "Date": "27-01-2021",
185 | "RollNo": 201751021,
186 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-44.pdf",
187 | "Email": "201851018@iiitvadodara.ac.in"
188 | },
189 | "IIITV/STUD-GYMKHANA/CERT/456/000045": {
190 | "Name": "Prem Shankar",
191 | "Sub Event Name": "Mystery Box",
192 | "Position": "1st",
193 | "Academic Year": "2019-2020",
194 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000045",
195 | "Date": "27-01-2021",
196 | "RollNo": 201751017,
197 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-45.pdf",
198 | "Email": "201851018@iiitvadodara.ac.in"
199 | },
200 | "IIITV/STUD-GYMKHANA/CERT/456/000046": {
201 | "Name": "Prakhar Gupta",
202 | "Sub Event Name": "Mystery Box",
203 | "Position": "1st",
204 | "Academic Year": "2019-2020",
205 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000046",
206 | "Date": "27-01-2021",
207 | "RollNo": 201751036,
208 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-46.pdf",
209 | "Email": "201851018@iiitvadodara.ac.in"
210 | },
211 | "IIITV/STUD-GYMKHANA/CERT/456/000047": {
212 | "Name": "Saurabh Tiwari",
213 | "Sub Event Name": "Mystery Box",
214 | "Position": "1st",
215 | "Academic Year": "2019-2020",
216 | "Certificate ID": "IIITV/STUD-GYMKHANA/CERT/456/000047",
217 | "Date": "27-01-2021",
218 | "RollNo": 201751047,
219 | "Filename": "IIITV-STUD-GYMKHANA-CERT-456-47.pdf",
220 | "Email": "201851018@iiitvadodara.ac.in"
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thepushkarp/certificate-generator-frontend/5024ac1c6c139da1c8f0226130d6afcab807643e/public/favicon-16x16.png
--------------------------------------------------------------------------------
/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thepushkarp/certificate-generator-frontend/5024ac1c6c139da1c8f0226130d6afcab807643e/public/favicon-32x32.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thepushkarp/certificate-generator-frontend/5024ac1c6c139da1c8f0226130d6afcab807643e/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
11 |
12 |
16 |
17 |
26 | IIITV Certificate Verification and Generation System
27 |
28 |
29 |
30 | You need to enable JavaScript to run this app.
31 |
32 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "IIITV Certificate Verification and Generation System",
3 | "name": "Indian Institute of Information Technology Vadodara's Certificate Verification and Generation System",
4 | "icons": [
5 | {
6 | "src": "/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | { "src": "/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" }
11 | ],
12 | "start_url": ".",
13 | "display": "standalone",
14 | "theme_color": "#000000",
15 | "background_color": "#ffffff"
16 | }
17 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
3 | import 'bootstrap/dist/css/bootstrap.min.css';
4 | import {
5 | Footer,
6 | Navigation,
7 | Home,
8 | Generate,
9 | Verify,
10 | Certificate,
11 | Login,
12 | } from './components';
13 |
14 | class App extends React.Component {
15 | constructor(props) {
16 | super(props);
17 |
18 | const loginToken = localStorage.getItem('token') ?? null;
19 | const time = localStorage.getItem('time') | '';
20 | const loginCheck = Boolean(!!loginToken && time < Date.now());
21 |
22 | this.state = {
23 | loginToken: loginToken,
24 | islogedIn: loginCheck,
25 | };
26 |
27 | this.handler = this.handler.bind(this);
28 | }
29 |
30 | componentDidMount() {
31 | const loginToken = localStorage.getItem('token') ?? null;
32 | const time = localStorage.getItem('time') | '';
33 | if (loginToken === null) {
34 | this.setState({
35 | islogedIn: false,
36 | });
37 | } else if (time < Date.now()) this.setState({ loginToken, islogedIn: true });
38 | }
39 |
40 | handler(token, cTime) {
41 | this.setState({
42 | loginToken: token,
43 | islogedIn: true,
44 | });
45 | localStorage.setItem('token', token);
46 | localStorage.setItem('time', cTime);
47 | }
48 |
49 | render() {
50 | const x = () => {
51 | const token = localStorage.getItem('token')
52 | ? localStorage.getItem('token')
53 | : '';
54 | const time = localStorage.getItem('time') | '';
55 | if (!!token && time < Date.now()) return true;
56 | return false;
57 | };
58 |
59 | return (
60 | <>
61 |
62 |
63 |
64 |
65 | {x() === false ? (
66 |
67 | ) : (
68 |
69 | )}
70 |
71 | }
75 | />
76 |
77 |
78 |
79 |
80 | } />
81 |
82 |
83 |
84 | >
85 | );
86 | }
87 | }
88 |
89 | export default App;
90 |
--------------------------------------------------------------------------------
/src/App.module.scss:
--------------------------------------------------------------------------------
1 | @media screen and (min-width: 320px) {
2 | /* smartphones, iPhone, portrait 480x320 phones */
3 | .contentMobile {
4 | display: block;
5 | }
6 | .contentDesktop {
7 | display: none;
8 | }
9 | }
10 |
11 | @media screen and (min-width: 481px) {
12 | /* portrait e-readers (Nook/Kindle), smaller tablets @ 600 or @ 640 wide. */
13 | .contentMobile {
14 | display: block;
15 | }
16 | .contentDesktop {
17 | display: none;
18 | }
19 | }
20 |
21 | @media screen and (min-width: 641px) {
22 | /* portrait tablets, portrait iPad, landscape e-readers, landscape 800x480 or 854x480 phones */
23 | .contentMobile {
24 | display: block;
25 | }
26 | .contentDesktop {
27 | display: none;
28 | }
29 | }
30 |
31 | @media screen and (min-width: 961px) {
32 | /* tablet, landscape iPad, lo-res laptops ands desktops */
33 | .contentMobile {
34 | display: none;
35 | }
36 | .contentDesktop {
37 | display: block;
38 | }
39 | }
40 |
41 | @media screen and (min-width: 1025px) {
42 | /* big landscape tablets, laptops, and desktops */
43 | .contentMobile {
44 | display: none;
45 | }
46 | .contentDesktop {
47 | display: block;
48 | }
49 | }
50 |
51 | @media screen and (min-width: 1281px) {
52 | /* hi-res laptops and desktops */
53 | .contentMobile {
54 | display: none;
55 | }
56 | .contentDesktop {
57 | display: block;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render( );
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/src/assets/club.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thepushkarp/certificate-generator-frontend/5024ac1c6c139da1c8f0226130d6afcab807643e/src/assets/club.jpg
--------------------------------------------------------------------------------
/src/assets/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thepushkarp/certificate-generator-frontend/5024ac1c6c139da1c8f0226130d6afcab807643e/src/assets/logo.jpg
--------------------------------------------------------------------------------
/src/components/Certificate.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { Button, Jumbotron } from 'react-bootstrap';
3 | import styles from '../css/FrontCertificate.module.css';
4 | import clsx from 'clsx';
5 |
6 | const Certificate = ({ match, location }) => {
7 | const [state, setstate] = useState({
8 | certificate: {
9 | id: '',
10 | cert_id: '',
11 | rollno: '',
12 | event: '',
13 | year: '',
14 | name: '',
15 | file: '',
16 | date: '',
17 | },
18 | });
19 |
20 | useEffect(() => {
21 | // console.log(match);
22 | const fetchData = async () => {
23 | const test = new FormData();
24 | test.append('id', match.params.id.split('-').join('/').split('_').join('-'));
25 | const res = await fetch('https://cert-iiit.ml/get', {
26 | method: 'POST',
27 | body: test,
28 | });
29 | const json = await res.json();
30 | setstate(json);
31 | };
32 | fetchData();
33 | }, [match]);
34 |
35 | return (
36 |
37 | {!state?.message ? (
38 | <>
39 | Found Successfully
40 |
41 | Name: {state.certificate.name}
42 | Roll: {state.certificate.rollno}
43 | Event: {state.certificate.event}
44 | Year: {state.certificate.year}
45 | Issued on: {state.certificate.date}
46 |
47 | Certificate ID: {state.certificate.cert_id}
48 |
49 | {state.certificate.file ? (
50 | <>
51 |
52 | Certificate:
53 |
68 | >
69 | ) : null}
70 | >
71 | ) : (
72 |
73 | Sorry This ID does not exist!
74 |
75 | )}
76 |
77 |
85 |
86 | );
87 | };
88 |
89 | export default Certificate;
90 |
--------------------------------------------------------------------------------
/src/components/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class Footer extends React.Component {
4 | render() {
5 | return (
6 |
48 | );
49 | }
50 | }
51 |
52 | export default Footer;
53 |
--------------------------------------------------------------------------------
/src/components/Generate.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Jumbotron, Button, Row } from 'react-bootstrap';
3 | import { jsPDF } from 'jspdf';
4 | import JSZip from 'jszip';
5 | import { saveAs } from 'file-saver';
6 | import { withRouter } from 'react-router-dom';
7 |
8 | class Generate extends React.Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = {
12 | isUploadButtonPressed: false, //To check if user has pressed the upload button
13 | certImage: null, // Image of certificate
14 | labelIdx: -1, // Index of the label which is currently uploaded
15 | isImageUploadable: false,
16 | isCheckButtonPressed: false,
17 | resultData: [],
18 | columns: [],
19 | fields: [],
20 | };
21 | }
22 | componentDidMount() {
23 | this.cert_canvas = React.createRef();
24 |
25 | this.clearCanvas = this.clearCanvas.bind(this);
26 | this.addTexts = this.addTexts.bind(this);
27 | this.initCanvas = this.initCanvas.bind(this);
28 | this.onMouseUp = this.onMouseUp.bind(this);
29 | this.onMouseMove = this.onMouseMove.bind(this);
30 | this.onMouseDown = this.onMouseDown.bind(this);
31 | this.makeCertificate = this.makeCertificate.bind(this);
32 | this.downloadZip = this.downloadZip.bind(this);
33 | this.submitZip = this.submitZip.bind(this);
34 |
35 | // Dummy data
36 |
37 | this.result_data = [];
38 | this.certID = null;
39 | }
40 |
41 | /*
42 | Clears all text from canvas leaving only certificate image
43 | */
44 | clearCanvas = () => {
45 | const canvas = this.cert_canvas.current;
46 | const ctx = canvas.getContext('2d');
47 | ctx.clearRect(0, 0, canvas.width, canvas.height);
48 | ctx.drawImage(this.state.certImage, 0, 0);
49 | };
50 |
51 | /*
52 | Adds all the text from the text field to the respective location
53 | */
54 | addTexts = () => {
55 | const canvas = this.cert_canvas.current;
56 | const ctx = canvas.getContext('2d');
57 | this.clearCanvas();
58 |
59 | for (var field of this.state.fields) {
60 | // 0.0003 because it scaled the font well
61 | ctx.font = `${0.0003 * field.font * canvas.width}px sans-serif`;
62 | ctx.fillText(field.text, field.x, field.y);
63 | }
64 | };
65 |
66 | /*
67 | Creates the initial canvas and returns its context
68 | */
69 | initCanvas = () => {
70 | const canvas = this.cert_canvas.current;
71 | canvas.width = this.state.certImage.width;
72 | canvas.height = this.state.certImage.height;
73 | const ctx = canvas.getContext('2d');
74 | return ctx;
75 | };
76 |
77 | /*
78 | On leaving mouse click, sets all text dragging property to false
79 | */
80 | onMouseUp(e) {
81 | for (var field of this.state.fields) {
82 | field.isDragged = false;
83 | }
84 | this.setState({
85 | labelIdx: -1,
86 | });
87 | e.preventDefault();
88 | }
89 |
90 | /*
91 | Moves the text which is draggable, with mouse movement
92 | */
93 | onMouseMove(e) {
94 | const canvas = this.cert_canvas.current;
95 | const ctx = canvas.getContext('2d');
96 | const i = this.state.labelIdx;
97 | if (i !== -1 && this.state.fields[i].isDragged) {
98 | const scaledCanvas = canvas.getBoundingClientRect();
99 | const canX =
100 | ((e.pageX - scaledCanvas.left - window.scrollX) / scaledCanvas.width) *
101 | canvas.width;
102 | const canY =
103 | ((e.pageY - scaledCanvas.top - window.scrollY) / scaledCanvas.height) *
104 | canvas.height;
105 | const field = this.state.fields[i];
106 | const fontSize = 0.0003 * field.font * canvas.width;
107 | const textLength = ctx.measureText(field.text).width;
108 | field.x = canX - textLength / 2;
109 | field.y = canY + fontSize / 2;
110 | this.addTexts();
111 | }
112 | e.preventDefault();
113 | }
114 |
115 | /*
116 | Searches the box where the pointer is and sets its draggable property to true
117 | */
118 | onMouseDown(e) {
119 | const canvas = this.cert_canvas.current;
120 | const ctx = canvas.getContext('2d');
121 | const scaledCanvas = canvas.getBoundingClientRect();
122 | const canX =
123 | ((e.pageX - scaledCanvas.left - window.scrollX) / scaledCanvas.width) *
124 | canvas.width;
125 | const canY =
126 | ((e.pageY - scaledCanvas.top - window.scrollY) / scaledCanvas.height) *
127 | canvas.height;
128 | var i,
129 | x,
130 | y,
131 | flag = false;
132 | for (i in this.state.fields) {
133 | const field = this.state.fields[i];
134 | // 0.0003 because it scaled the font well
135 | const fontSize = 0.0003 * field.font * canvas.width;
136 | const textLength = field.text.length * fontSize;
137 | const textHeight = fontSize;
138 | x = field.x;
139 | y = field.y;
140 | if (canX < x + textLength && canX > x && canY > y - textHeight && canY < y) {
141 | flag = true;
142 | break;
143 | }
144 | }
145 | if (flag === true) {
146 | this.setState({
147 | labelIdx: i,
148 | });
149 | const field = this.state.fields[i];
150 | const fontSize = 0.0003 * field.font * canvas.width;
151 | const textLength = ctx.measureText(field.text).width;
152 | field.x = canX - textLength / 2;
153 | field.y = canY + fontSize / 2;
154 | field.isDragged = true;
155 | this.addTexts();
156 | }
157 | e.preventDefault();
158 | }
159 |
160 | /*
161 | Creates the certificate initially and add texts with default location
162 | */
163 | makeCertificate = () => {
164 | const ctx = this.initCanvas();
165 | ctx.lineWidth = 1;
166 | this.addTexts();
167 | };
168 |
169 | /*
170 | Downloads the Zip of all the PDFs
171 | Implemented from: https://stackoverflow.com/a/56783750/10307491
172 | */
173 | downloadZip = () => {
174 | const canvas = this.cert_canvas.current;
175 | const ctx = canvas.getContext('2d');
176 | const quality = 0.5;
177 | const zip = new JSZip();
178 | const zipName = `certificate-${new Date()
179 | .toLocaleDateString('gu-IN')
180 | .split('/')
181 | .join('-')}.zip`;
182 |
183 | var initialfields = this.state.columns.map((ele, i) => {
184 | return {
185 | text: ele,
186 | x: this.state.fields[i].x,
187 | y: this.state.fields[i].y,
188 | font: 64,
189 | };
190 | });
191 | this.state.resultData.forEach((data) => {
192 | this.clearCanvas();
193 | for (var field of initialfields) {
194 | // 0.0003 because it scaled the font well
195 | ctx.font = `${0.0003 * field.font * canvas.width}px sans-serif`;
196 |
197 | ctx.fillText(data[field.text], field.x, field.y);
198 | }
199 |
200 | const imgData = canvas.toDataURL('image/jpeg', quality);
201 | const pdf = new jsPDF({
202 | orientation: 'landscape',
203 | unit: 'px',
204 | format: [canvas.width, canvas.height],
205 | });
206 | pdf.addImage(imgData, 'JPEG', 0, 0, canvas.width, canvas.height);
207 | var pdfName = data['Filename'];
208 |
209 | zip.file(pdfName, pdf.output('blob'));
210 | });
211 | zip.generateAsync({ type: 'blob' }).then(async (content) => {
212 | // console.dir(content)
213 | // .then((response) => console.log(response));
214 | saveAs(content, zipName);
215 | });
216 | };
217 | submitZip = () => {
218 | // eslint-disable-next-line react-hooks/rules-of-hooks
219 | const canvas = this.cert_canvas.current;
220 | const ctx = canvas.getContext('2d');
221 | const quality = 0.5;
222 | const zip = new JSZip();
223 | var initialfields = this.state.columns.map((ele, i) => {
224 | return {
225 | text: ele,
226 | x: this.state.fields[i].x,
227 | y: this.state.fields[i].y,
228 | font: 64,
229 | };
230 | });
231 | this.state.resultData.forEach((data) => {
232 | this.clearCanvas();
233 | for (var field of initialfields) {
234 | // 0.0003 because it scaled the font well
235 | ctx.font = `${0.0003 * field.font * canvas.width}px sans-serif`;
236 |
237 | ctx.fillText(data[field.text], field.x, field.y);
238 | }
239 |
240 | const imgData = canvas.toDataURL('image/jpeg', quality);
241 | const pdf = new jsPDF({
242 | orientation: 'landscape',
243 | unit: 'px',
244 | format: [canvas.width, canvas.height],
245 | });
246 | pdf.addImage(imgData, 'JPEG', 0, 0, canvas.width, canvas.height);
247 | var pdfName = data['Filename'];
248 |
249 | zip.file(pdfName, pdf.output('blob'));
250 | });
251 | zip.generateAsync({ type: 'blob' }).then(async (content) => {
252 | // console.dir(content);
253 | const uploadData = new FormData();
254 | const token = localStorage.getItem('token');
255 | uploadData.append('id', this.state.certID);
256 | uploadData.append('zip', content);
257 | uploadData.append('token', token);
258 | await fetch('https://cert-iiit.ml/upload', {
259 | method: 'POST',
260 | body: uploadData,
261 | }).then(() => this.props.history.push('/'));
262 | // saveAs(content, zipName);
263 | });
264 | };
265 |
266 | uploadData = () => {
267 | return (
268 |
269 | Upload Data
270 |
368 |
369 | );
370 | };
371 |
372 | /*
373 | Replaces default placeholder data with real data to see how the certificate
374 | looks
375 | */
376 | replaceText = () => {
377 | if (this.state.isCheckButtonPressed === false) {
378 | const firstData = this.state.resultData[0];
379 | this.originalFields = [];
380 | for (var field of this.state.fields) {
381 | this.originalFields.push({ ...field });
382 | field.text = firstData[field.text];
383 | }
384 | this.addTexts();
385 | this.setState({
386 | isCheckButtonPressed: true,
387 | });
388 | }
389 | // console.log(this.originalFields);
390 | };
391 |
392 | render() {
393 | return (
394 | <>
395 |
401 | Drag the labels to appropriate positions
402 |
413 |
414 | {
420 | this.replaceText();
421 | }}
422 | className="ml-3"
423 | >
424 | Check
425 |
426 | {
431 | this.downloadZip();
432 | }}
433 | className="ml-3"
434 | >
435 | Download Certificates
436 |
437 | {
442 | this.submitZip();
443 | }}
444 | className="ml-3"
445 | >
446 | Submit Certificates
447 |
448 |
449 |
450 |
458 |
459 | {!this.state.isUploadButtonPressed && this.uploadData()}
460 | >
461 | );
462 | }
463 | }
464 |
465 | export default withRouter(Generate);
466 |
--------------------------------------------------------------------------------
/src/components/Home.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | import { Jumbotron, Button } from 'react-bootstrap';
4 |
5 | class Home extends React.Component {
6 | render() {
7 | return (
8 |
9 | Verify Certificates
10 |
11 | This is the certificate verification site for Indian Institute of
12 | Information Technology Vadodara
13 |
14 |
15 | Click here to verify the certificates!
16 |
17 |
18 | Verify
19 |
20 |
21 |
22 | );
23 | }
24 | }
25 |
26 | export default Home;
27 |
--------------------------------------------------------------------------------
/src/components/Login.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { Jumbotron, Button } from 'react-bootstrap';
3 | import { useHistory } from 'react-router-dom';
4 |
5 | const Login = (props) => {
6 | const history = useHistory();
7 |
8 | useEffect(() => {
9 | if (props.islogedIn) {
10 | history.push('/');
11 | }
12 | }, [props, history]);
13 |
14 | return (
15 |
16 | Superuser Login
17 |
55 |
56 | );
57 | };
58 |
59 | export default Login;
60 |
--------------------------------------------------------------------------------
/src/components/Navigation.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Nav, Navbar } from 'react-bootstrap';
3 | import logo from '../assets/logo.jpg';
4 |
5 | class Navigation extends React.Component {
6 | render() {
7 | return (
8 |
9 |
14 |
21 |
22 |
23 |
24 |
25 | Home
26 | {this.props.islogedIn ? (
27 | Generate Certificates
28 | ) : null}
29 | Verify Certificates
30 |
31 |
32 |
33 | );
34 | }
35 | }
36 |
37 | export default Navigation;
38 |
--------------------------------------------------------------------------------
/src/components/Verify.jsx:
--------------------------------------------------------------------------------
1 | import clsx from 'clsx';
2 | import React, { Component } from 'react';
3 | import styles from '../css/Verify.module.css';
4 | import { Redirect } from 'react-router-dom';
5 | import { withRouter } from 'react-router-dom';
6 | import { message, fail } from '../css/FrontCertificate.module.css';
7 | import { Jumbotron, Button } from 'react-bootstrap';
8 |
9 | export class Verify extends Component {
10 | constructor(props) {
11 | super(props);
12 |
13 | this.state = {
14 | data: null,
15 | isRollno: true,
16 | };
17 | }
18 |
19 | render() {
20 | // console.log(this.state);
21 | if (!this.state.isRollno) {
22 | return ;
23 | } else {
24 | return (
25 | <>
26 |
27 | {!!this.state.data && !this.state.data?.message ? (
28 | <>
29 | Certificates Found
30 |
31 |
32 |
33 | Name
34 | Event
35 | Year
36 | Certificate ID
37 |
38 |
39 |
40 | {this.state.data.certificates.map((ele, index) => {
41 | return (
42 |
43 | {ele.name}
44 | {ele.event}
45 | {ele.year}
46 |
47 |
56 | {ele.cert_id}
57 |
58 |
59 |
60 | );
61 | })}
62 |
63 |
64 |
65 |
78 | >
79 | ) : this.state.data?.message ? (
80 | <>
81 | Sorry, this ID does not exist!
82 |
95 | >
96 | ) : (
97 | <>
98 |
99 | Enter the Roll Number or the Certificate ID
100 |
101 |
136 | >
137 | )}
138 |
139 | >
140 | );
141 | }
142 | }
143 | }
144 |
145 | export default withRouter(Verify);
146 |
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | export { default as Navigation } from './Navigation';
2 | export { default as Footer } from './Footer';
3 | export { default as Home } from './Home';
4 | export { default as Generate } from './Generate';
5 | export { default as Verify } from './Verify';
6 | export { default as Certificate } from './Certificate';
7 | export { default as Login } from './Login';
8 |
--------------------------------------------------------------------------------
/src/css/FrontCertificate.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | padding: 16px;
3 | background-color: #e9ecef;
4 | }
5 | .details {
6 | padding: 5px 0;
7 | font-size: 24px;
8 | color: rgba(0, 0, 0, 0.75);
9 | font-weight: 100;
10 | }
11 |
12 | .message {
13 | padding: 10px;
14 | width: 100%;
15 | }
16 |
17 | .success {
18 | border: 2px solid green;
19 | background-color: #d4edda;
20 | color: green;
21 | }
22 | .fail {
23 | border: 2px solid red;
24 | background-color: #ff9497;
25 | color: red;
26 | }
27 |
--------------------------------------------------------------------------------
/src/css/Login.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #e9ecef;
3 | padding: 64px 32px;
4 | }
5 |
6 | .input {
7 | margin: 0 10px;
8 | }
9 |
--------------------------------------------------------------------------------
/src/css/Verify.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | width: 100vw;
3 | height: max-content;
4 | background-color: #e9ecef;
5 | padding: 64px 32px;
6 | }
7 |
8 | .btn {
9 | width: 0;
10 | height: 0;
11 | padding: 0;
12 | margin: 0;
13 | border-width: 0;
14 | padding: 8px 16px;
15 | background-color: #007bff;
16 | border-radius: 8px;
17 | margin: 10px;
18 | height: max-content;
19 | width: max-content;
20 | color: #fff;
21 | font-size: 20px;
22 | }
23 |
24 | .btn:hover {
25 | background-color: #026ddf;
26 | cursor: pointer;
27 | }
28 |
29 | .btn:focus {
30 | outline: none;
31 | }
32 | .sub {
33 | padding: 8px 16px;
34 | background-color: #28a745;
35 | }
36 | .input {
37 | margin: 0 2px;
38 | }
39 |
40 | .table {
41 | width: 100%;
42 | }
43 |
44 | .table_header {
45 | background-color: #343a40;
46 | color: #fff;
47 | }
48 |
49 | .table_data {
50 | padding: 10px;
51 | }
52 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
5 | -webkit-font-smoothing: antialiased;
6 | -moz-osx-font-smoothing: grayscale;
7 | }
8 |
9 | code {
10 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
11 | }
12 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | ReactDOM.render(
8 |
9 |
10 | ,
11 | document.getElementById('root')
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = (onPerfEntry) => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------