diff --git a/Readme.md b/Readme.md
index 5eb1bb2..79dbcbb 100644
--- a/Readme.md
+++ b/Readme.md
@@ -7,17 +7,16 @@
[![Twitter Follow](https://img.shields.io/twitter/follow/eventyay.svg?style=social&label=Follow&maxAge=2592000?style=flat-square)](https://twitter.com/eventyay)
## Communication
-
-Please join our [Mailing list](https://groups.google.com/forum/#!forum/open-event) or [chat channel](https://gitter.im/fossasia/open-event-frontend) to get in touch with the developers.
+Please join our [mailing list](https://groups.google.com/forum/#!forum/open-event) or [chat channel](https://gitter.im/fossasia/open-event-frontend) to get in touch with the developers.
## Installation
-
Easily deployed on a variety of platforms. Detailed platform specific instructions have been provided below.
+
### Local
-Clone or Fork the codebase and following instructions [below](https://github.com/fossasia/open-event-checkin/tree/development/.github/workflows)
+Clone or Fork the codebase and following instructions [below](#running--development).
### Github Pages (using Github Actions)
-Refer to our [workflow](https://github.com/fossasia/open-event-checkin/tree/development/.github/workflows) for deployment
+Refer to the [workflow](https://github.com/fossasia/open-event-checkin/tree/development/.github/workflows) for deployment.
## Running / Development
@@ -69,13 +68,11 @@ npm build
**Master branch**
-Deployed in a production environment at [https://checkin.eventyay.com](https://checkin-eventyay.com)
-It consumes the API exposed by master branch deployment of open event server, hosted at [https://api.eventyay.com](https://api.eventyay.com)
+Deployed in a production environment at [checkin.eventyay.com](https://checkin.eventyay.com) it consumes the API exposed by master branch deployment of open event server, hosted at [api.eventyay.com](https://api.eventyay.com).
#### Development branch
-Only deployed locally with `npm run dev` or Netlify version when you make a pull request
-It consumes the API exposed by development branch of open event server, hosted at [https://test-api.eventyay.com](https://test-api.eventyay.com)
+Only deployed locally with `npm run dev` or Netlify when you make a pull request it consumes the API exposed by development branch of open event server, hosted at [test-api.eventyay.com](https://test-api.eventyay.com).
## Further Reading / Useful Links
@@ -98,9 +95,9 @@ It consumes the API exposed by development branch of open event server, hosted a
### Commits
-- Write clear meaningful git commit messages (Do read [https://chris.beams.io/posts/git-commit/](https://chris.beams.io/posts/git-commit/))
-- Make sure your PR's description contains GitHub's special keyword references that automatically close the related issue when the PR is merged. (More info at [https://github.com/blog/1506-closing-issues-via-pull-requests](https://github.com/blog/1506-closing-issues-via-pull-requests) )
-- When you make very minor changes to a PR of yours (like for example fixing a failing Travis build or some small style corrections or minor changes requested by reviewers) make sure you squash your commits afterward so that you don't have an absurd number of commits for a very small fix. (Learn how to squash at [https://davidwalsh.name/squash-commits-git](https://davidwalsh.name/squash-commits-git) )
+- Write clear meaningful git commit messages (Do read [chris.beams.io/posts/git-commit/](https://chris.beams.io/posts/git-commit/))
+- Make sure your PR's description contains GitHub's special keyword references that automatically close the related issue when the PR is merged. (More info at [github.com/blog/1506-closing-issues-via-pull-requests](https://github.com/blog/1506-closing-issues-via-pull-requests) )
+- When you make very minor changes to a PR of yours (like for example fixing a failing Travis build or some small style corrections or minor changes requested by reviewers) make sure you squash your commits afterward so that you don't have an absurd number of commits for a very small fix. (Learn how to squash at [davidwalsh.name/squash-commits-git](https://davidwalsh.name/squash-commits-git) )
- When you're submitting a PR for a UI-related issue, it would be really awesome if you add a screenshot of your change or a link to a deployment where it can be tested out along with your PR. It makes it very easy for the reviewers and you'll also get reviews quicker.
### Feature Requests and Bug Reports
@@ -116,4 +113,4 @@ When you file a feature request or when you are submitting a bug report to the [
This project is currently licensed under the [Apache License version 2.0](LICENSE).
-To obtain the software under a different license, Please contact **[FOSSASIA](https://blog.fossasia.org/contact/)**.
+To obtain the software under a different license, Please contact [FOSSASIA](https://blog.fossasia.org/contact/).
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 3332041..fb1c401 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,7 +14,7 @@
"mande": "^2.0.6",
"pinia": "^2.1.3",
"vue": "^3.3.4",
- "vue-qrcode-reader": "3.1.0-vue3-compatibility.2",
+ "vue-qrcode-reader": "^5.3.4",
"vue-router": "^4.2.2"
},
"devDependencies": {
@@ -713,6 +713,24 @@
"integrity": "sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw==",
"dev": true
},
+ "node_modules/@sec-ant/barcode-detector": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@sec-ant/barcode-detector/-/barcode-detector-1.3.1.tgz",
+ "integrity": "sha512-JeQ9OnDNN1hYM7pxLpD0jhI7isnSkBTC+oxqqBfCtCzCDyr+807ouvjLbIUrHdZPp+7AaJhnYBdp09R++Z/POA==",
+ "dependencies": {
+ "@sec-ant/zxing-wasm": "^2.1.3",
+ "@types/dom-webcodecs": "^0.1.8"
+ }
+ },
+ "node_modules/@sec-ant/zxing-wasm": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@sec-ant/zxing-wasm/-/zxing-wasm-2.1.4.tgz",
+ "integrity": "sha512-7KmKMvN5nT4AL5hrXzTouO6MBSK4mZladSaiYT7gDqEMRiHcEKBfrgV3f0KwWeUSexzouQMJrczYvobXtXl3Ig==",
+ "dependencies": {
+ "@types/emscripten": "^1.39.7",
+ "zustand": "^4.4.1"
+ }
+ },
"node_modules/@sideway/address": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
@@ -770,6 +788,16 @@
"@types/chai": "*"
}
},
+ "node_modules/@types/dom-webcodecs": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.8.tgz",
+ "integrity": "sha512-KThTPaGQJLITk8Q0XkEkz+GqFdoWDyQfbyeJmfEUagB15TZQdNx5AqP2b7GP6vkVM6X/6T1Z8EHxA8RgHfY9BA=="
+ },
+ "node_modules/@types/emscripten": {
+ "version": "1.39.7",
+ "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.7.tgz",
+ "integrity": "sha512-tLqYV94vuqDrXh515F/FOGtBcRMTPGvVV1LzLbtYDcQmmhtpf/gLYf+hikBbQk8MzOHNz37wpFfJbYAuSn8HqA=="
+ },
"node_modules/@types/estree": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
@@ -914,19 +942,6 @@
"url": "https://opencollective.com/vitest"
}
},
- "node_modules/@vue/compat": {
- "version": "3.3.4",
- "resolved": "https://registry.npmjs.org/@vue/compat/-/compat-3.3.4.tgz",
- "integrity": "sha512-VwAsPqUqRJVxeLQPUC03Sa5d+T8UG2Qv4VItq74KmNvtQlRXICpa/sqq12BcyBB4Tz1U5paOEZxWCUoXkrZ9QQ==",
- "dependencies": {
- "@babel/parser": "^7.21.3",
- "estree-walker": "^2.0.2",
- "source-map-js": "^1.0.2"
- },
- "peerDependencies": {
- "vue": "3.3.4"
- }
- },
"node_modules/@vue/compiler-core": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz",
@@ -1066,26 +1081,6 @@
"vue": "^3.0.1"
}
},
- "node_modules/@zxing/library": {
- "version": "0.18.6",
- "resolved": "https://registry.npmjs.org/@zxing/library/-/library-0.18.6.tgz",
- "integrity": "sha512-bulZ9JHoLFd9W36pi+7e7DnEYNJhljYjZ1UTsKPOoLMU3qtC+REHITeCRNx40zTRJZx18W5TBRXt5pq2Uopjsw==",
- "dependencies": {
- "ts-custom-error": "^3.0.0"
- },
- "engines": {
- "node": ">= 10.4.0"
- },
- "optionalDependencies": {
- "@zxing/text-encoding": "~0.9.0"
- }
- },
- "node_modules/@zxing/text-encoding": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz",
- "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==",
- "optional": true
- },
"node_modules/abab": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
@@ -1435,15 +1430,6 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
- "node_modules/barcode-detector": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-1.0.3.tgz",
- "integrity": "sha512-pQY+sPhY2aZ9hdLJnniY5zcsaDXSpymTWtVbZHbmJPVCRt7HnYYfXLLHQ4rEYOvahEML3oJ71VjwBc80hS0RvQ==",
- "dependencies": {
- "@zxing/library": "^0.18.4",
- "jsqr": "^1.3.1"
- }
- },
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -1624,11 +1610,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/callforth": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/callforth/-/callforth-0.3.1.tgz",
- "integrity": "sha512-Q2zPfqnwoKsb1DTVCr4lmhe49wKNBsMmNlbudjleu3/co+Nw1pOqFHYJHrW3VZ253ou9AAr+xauQR0C55NPdzA=="
- },
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -1962,16 +1943,6 @@
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
"dev": true
},
- "node_modules/core-js": {
- "version": "3.31.0",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.31.0.tgz",
- "integrity": "sha512-NIp2TQSGfR6ba5aalZD+ZQ1fSxGhDo/s1w0nx3RYzf2pnJxt7YynxFlFScP6eV7+GZsKO95NSjGxyJsU3DZgeQ==",
- "hasInstallScript": true,
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/core-js"
- }
- },
"node_modules/core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
@@ -3524,6 +3495,12 @@
"node": ">= 0.8"
}
},
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "peer": true
+ },
"node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
@@ -3679,11 +3656,6 @@
"verror": "1.10.0"
}
},
- "node_modules/jsqr": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/jsqr/-/jsqr-1.4.0.tgz",
- "integrity": "sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A=="
- },
"node_modules/lazy-ass": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz",
@@ -3865,6 +3837,18 @@
"node": ">=8"
}
},
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "peer": true,
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
"node_modules/loupe": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
@@ -4869,6 +4853,18 @@
}
]
},
+ "node_modules/react": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
+ "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
+ "peer": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -5023,18 +5019,6 @@
"integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==",
"dev": true
},
- "node_modules/rtcpeerconnection-shim": {
- "version": "1.2.15",
- "resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz",
- "integrity": "sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==",
- "dependencies": {
- "sdp": "^2.6.0"
- },
- "engines": {
- "node": ">=6.0.0",
- "npm": ">=3.10.0"
- }
- },
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -5106,9 +5090,9 @@
}
},
"node_modules/sdp": {
- "version": "2.12.0",
- "resolved": "https://registry.npmjs.org/sdp/-/sdp-2.12.0.tgz",
- "integrity": "sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw=="
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz",
+ "integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw=="
},
"node_modules/semver": {
"version": "7.5.2",
@@ -5681,14 +5665,6 @@
"node": ">=14"
}
},
- "node_modules/ts-custom-error": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.3.1.tgz",
- "integrity": "sha512-5OX1tzOjxWEgsr/YEUWSuPrQ00deKLh6D7OTWcvNHm12/7QPyRh8SYpyWvA4IZv8H/+GQWQEh/kwo95Q9OVW1A==",
- "engines": {
- "node": ">=14.0.0"
- }
- },
"node_modules/ts-interface-checker": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
@@ -5839,6 +5815,14 @@
"requires-port": "^1.0.0"
}
},
+ "node_modules/use-sync-external-store": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
+ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -6054,16 +6038,15 @@
}
},
"node_modules/vue-qrcode-reader": {
- "version": "3.1.0-vue3-compatibility.2",
- "resolved": "https://registry.npmjs.org/vue-qrcode-reader/-/vue-qrcode-reader-3.1.0-vue3-compatibility.2.tgz",
- "integrity": "sha512-tGu2zmPGSi9SJR08Yl2favix0vs5SgXudGXdwW2KxcvlU9jfsX9FAYkuaifyiq3CgxKijwRxA/YJpS0Yl9PMfw==",
+ "version": "5.3.4",
+ "resolved": "https://registry.npmjs.org/vue-qrcode-reader/-/vue-qrcode-reader-5.3.4.tgz",
+ "integrity": "sha512-pWF4Vhj/J2tVYP8VIQKue6Pl9K1ccA9iadG+u6LGnIYjwxVDZRDoXQYpKRX8IfYKFgSkRMQhLlj0xwCLiw7YdQ==",
"dependencies": {
- "@vue/compat": "^3.1.0",
- "barcode-detector": "^1.0.0",
- "callforth": "^0.3.1",
- "core-js": "^3.6.5",
- "vue": "^3.1.0",
- "webrtc-adapter": "7.7.0"
+ "@sec-ant/barcode-detector": "^1.2.2",
+ "webrtc-adapter": "^8.2.3"
+ },
+ "engines": {
+ "node": ">=18.0.0"
}
},
"node_modules/vue-router": {
@@ -6121,12 +6104,11 @@
}
},
"node_modules/webrtc-adapter": {
- "version": "7.7.0",
- "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.7.0.tgz",
- "integrity": "sha512-7Bp9OBnx642oJRkom1tNAbeJjUadAq2rh5xLL9YXPw5hVyt2h4hHr5bcoPYDs1stp/mZHSPSQA34YISdnr0DBQ==",
+ "version": "8.2.3",
+ "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-8.2.3.tgz",
+ "integrity": "sha512-gnmRz++suzmvxtp3ehQts6s2JtAGPuDPjA1F3a9ckNpG1kYdYuHWYpazoAnL9FS5/B21tKlhkorbdCXat0+4xQ==",
"dependencies": {
- "rtcpeerconnection-shim": "^1.2.15",
- "sdp": "^2.12.0"
+ "sdp": "^3.2.0"
},
"engines": {
"node": ">=6.0.0",
@@ -6302,6 +6284,33 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
+ },
+ "node_modules/zustand": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.1.tgz",
+ "integrity": "sha512-QCPfstAS4EBiTQzlaGP1gmorkh/UL1Leaj2tdj+zZCZ/9bm0WS7sI2wnfD5lpOszFqWJ1DcPnGoY8RDL61uokw==",
+ "dependencies": {
+ "use-sync-external-store": "1.2.0"
+ },
+ "engines": {
+ "node": ">=12.7.0"
+ },
+ "peerDependencies": {
+ "@types/react": ">=16.8",
+ "immer": ">=9.0",
+ "react": ">=16.8"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "immer": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ }
+ }
}
}
}
diff --git a/package.json b/package.json
index 9166560..063ab33 100644
--- a/package.json
+++ b/package.json
@@ -4,6 +4,7 @@
"private": true,
"scripts": {
"dev": "vite",
+ "build:staging": "vite build --mode staging",
"build": "vite build",
"preview": "vite preview --port 8080 --host",
"test:unit": "vitest",
@@ -19,7 +20,7 @@
"mande": "^2.0.6",
"pinia": "^2.1.3",
"vue": "^3.3.4",
- "vue-qrcode-reader": "3.1.0-vue3-compatibility.2",
+ "vue-qrcode-reader": "^5.3.4",
"vue-router": "^4.2.2"
},
"devDependencies": {
diff --git a/public/test-badge.pdf b/public/test-badge.pdf
new file mode 100644
index 0000000..51967bd
Binary files /dev/null and b/public/test-badge.pdf differ
diff --git a/src/components/QRScanner/ScannerCamera.vue b/src/components/CheckIn/CheckInCamera.vue
similarity index 79%
rename from src/components/QRScanner/ScannerCamera.vue
rename to src/components/CheckIn/CheckInCamera.vue
index e88de4b..a0020fb 100644
--- a/src/components/QRScanner/ScannerCamera.vue
+++ b/src/components/CheckIn/CheckInCamera.vue
@@ -15,7 +15,10 @@ const scannerType = route.params.scannerType
const microlocationId = route.params.stationId
onBeforeMount(async () => {
- await sessionsStore.getCurrentSession(microlocationId)
+ if (scannerType !== 'daily') {
+ await sessionsStore.getCurrentSession(microlocationId)
+ }
+ processCheckInStore.$reset()
loadingStore.contentLoaded()
})
@@ -27,10 +30,10 @@ onBeforeMount(async () => {
- {{ processCheckInStore.response.message }}
diff --git a/src/components/QRScanner/ScannedStats.vue b/src/components/CheckIn/CheckInStats.vue
similarity index 95%
rename from src/components/QRScanner/ScannedStats.vue
rename to src/components/CheckIn/CheckInStats.vue
index d0c05b6..b1a075c 100644
--- a/src/components/QRScanner/ScannedStats.vue
+++ b/src/components/CheckIn/CheckInStats.vue
@@ -11,6 +11,7 @@ const statsStore = useStatsStore()
const sessionsStore = useSessionsStore()
const route = useRoute()
const eventId = route.params.eventId
+const scannerType = route.params.scannerType
const microlocationId = route.params.stationId
const sessionStats = ref([
@@ -52,7 +53,7 @@ onBeforeMount(async () => {
Stats
-
+
Current Session: {{ sessionsStore.currentSessionName }}
@@ -86,5 +87,6 @@ onBeforeMount(async () => {
+
Work in progress
diff --git a/src/components/Common/QRCamera.vue b/src/components/Common/QRCamera.vue
index 5820ddf..ddc1ea6 100644
--- a/src/components/Common/QRCamera.vue
+++ b/src/components/Common/QRCamera.vue
@@ -1,6 +1,7 @@
diff --git a/src/components/LoginForm.vue b/src/components/LoginForm.vue
index 0ad411a..2a30444 100644
--- a/src/components/LoginForm.vue
+++ b/src/components/LoginForm.vue
@@ -3,11 +3,13 @@ import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useLoadingStore } from '@/stores/loading'
import { useAuthStore } from '@/stores/auth'
+import { useUserStore } from '@/stores/user'
import StandardButton from '@/components/Common/StandardButton.vue'
// stores
const loadingStore = useLoadingStore()
const authStore = useAuthStore()
+const userStore = useUserStore()
const email = ref('')
const password = ref('')
@@ -28,8 +30,9 @@ async function submitLogin() {
await authStore
.login(payload)
.then(async () => {
+ await userStore.getUserDetails()
router.push({
- name: 'stationSelector'
+ name: 'selectStation'
})
})
.catch((err) => {
@@ -42,7 +45,7 @@ async function submitLogin() {
onMounted(() => {
if (authStore.isAuthenticated) {
router.push({
- name: 'stationSelector'
+ name: 'selectStation'
})
}
diff --git a/src/components/NavBar.vue b/src/components/NavBar.vue
index 8c38fc3..ca24e1e 100644
--- a/src/components/NavBar.vue
+++ b/src/components/NavBar.vue
@@ -1,39 +1,31 @@
diff --git a/src/components/Registration/Kiosk/ScannerCamera.vue b/src/components/Registration/Kiosk/KioskOverview.vue
similarity index 100%
rename from src/components/Registration/Kiosk/ScannerCamera.vue
rename to src/components/Registration/Kiosk/KioskOverview.vue
diff --git a/src/components/Registration/Manual/RegistrationStats.vue b/src/components/Registration/Station/RegistrationStats.vue
similarity index 100%
rename from src/components/Registration/Manual/RegistrationStats.vue
rename to src/components/Registration/Station/RegistrationStats.vue
diff --git a/src/components/Registration/Manual/SearchAttendee.vue b/src/components/Registration/Station/SearchAttendee.vue
similarity index 98%
rename from src/components/Registration/Manual/SearchAttendee.vue
rename to src/components/Registration/Station/SearchAttendee.vue
index 3e66c71..fb7672b 100644
--- a/src/components/Registration/Manual/SearchAttendee.vue
+++ b/src/components/Registration/Station/SearchAttendee.vue
@@ -52,7 +52,7 @@ const selectedFields = ref([])
watch(query, async (newValue) => {
if (newValue === '' || newValue === null) {
- setTimeout(() => attendeesStore.clearAttendees(), 700)
+ setTimeout(() => attendeesStore.$reset, 700)
} else {
isFetchingFiltered.value = true
await attendeesStore.fetchAttendees(
@@ -217,7 +217,7 @@ const filteredAttendees = computed(() => {
@@ -282,7 +282,7 @@ const filteredAttendees = computed(() => {
v-if="query !== '' && isFetchingFiltered"
class="mt-5 flex flex-col justify-start rounded-md py-14 text-center text-sm ring-1 ring-secondary"
>
- Fetching attendees. Please wait...
+ Fetching attendees. Please wait...
diff --git a/src/components/Registration/Manual/ScanSearch.vue b/src/components/Registration/Station/StationOverview.vue
similarity index 89%
rename from src/components/Registration/Manual/ScanSearch.vue
rename to src/components/Registration/Station/StationOverview.vue
index ef41879..ec70dc5 100644
--- a/src/components/Registration/Manual/ScanSearch.vue
+++ b/src/components/Registration/Station/StationOverview.vue
@@ -1,6 +1,6 @@
@@ -159,6 +143,7 @@ async function submitForm() {
>
stationSelectorStore.$patch({ selectedMicrolocation: n })"
+ :selected-option="stationSelectorStore.selectedStation"
+ @update-selected="(n) => stationSelectorStore.$patch({ selectedStation: n })"
>
diff --git a/src/components/Utilities/QRCamera.vue b/src/components/Utilities/QRCamera.vue
index c460b7b..bbd1348 100644
--- a/src/components/Utilities/QRCamera.vue
+++ b/src/components/Utilities/QRCamera.vue
@@ -1,4 +1,5 @@
+
diff --git a/src/router/index.js b/src/router/index.js
index 9b12f5b..b3ac7d6 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -1,14 +1,14 @@
import AuthTemplate from '@/AuthTemplate.vue'
-import ScannedStats from '@/components/QRScanner/ScannedStats.vue'
-import QRScannerCamera from '@/components/QRScanner/ScannerCamera.vue'
-import RegistrationKiosk from '@/components/Registration/Kiosk/ScannerCamera.vue'
-import RegistrationStats from '@/components/Registration/Manual/RegistrationStats.vue'
-import RegistrationManual from '@/components/Registration/Manual/ScanSearch.vue'
+import CheckInCamera from '@/components/CheckIn/CheckInCamera.vue'
+import CheckInStats from '@/components/CheckIn/CheckInStats.vue'
+import RegistrationKiosk from '@/components/Registration/Kiosk/KioskOverview.vue'
+import RegistrationStats from '@/components/Registration/Station/RegistrationStats.vue'
+import RegistrationStation from '@/components/Registration/Station/StationOverview.vue'
import { useLoadingStore } from '@/stores/loading'
+import CheckInView from '@/views/CheckInView.vue'
import NotFound from '@/views/NotFound.vue'
-import RegistrationStation from '@/views/RegistrationStation.vue'
-import ScannerTemplate from '@/views/ScannerTemplate.vue'
-import StationSelector from '@/views/StationSelector.vue'
+import RegistrationView from '@/views/RegistrationView.vue'
+import SelectStation from '@/views/SelectStation.vue'
import UserAuth from '@/views/UserAuth.vue'
import { createRouter, createWebHistory } from 'vue-router'
@@ -26,15 +26,15 @@ const router = createRouter({
component: AuthTemplate,
children: [
{
- path: 'station-selector',
- name: 'stationSelector',
- component: StationSelector
+ path: 'select-station',
+ name: 'selectStation',
+ component: SelectStation
},
{
path: ':eventId/registration/:registrationType/:stationId',
name: 'registration',
redirect: { name: 'registerKiosk' },
- component: RegistrationStation,
+ component: RegistrationView,
children: [
{
path: 'kiosk',
@@ -42,9 +42,9 @@ const router = createRouter({
component: RegistrationKiosk
},
{
- path: 'search',
- name: 'registerHybrid',
- component: RegistrationManual
+ path: 'station',
+ name: 'registerStation',
+ component: RegistrationStation
},
{
path: 'stats',
@@ -55,20 +55,20 @@ const router = createRouter({
},
{
// stationId = microlocation over here
- path: ':eventId/:stationId/scanner/:scannerType',
- name: 'scanner',
- redirect: { name: 'scannerCamera' },
- component: ScannerTemplate,
+ path: ':eventId/:stationId/:scannerType',
+ name: 'checkIn',
+ redirect: { name: 'checkInCamera' },
+ component: CheckInView,
children: [
{
- path: 'camera',
- name: 'scannerCamera',
- component: QRScannerCamera
+ path: 'station',
+ name: 'checkInCamera',
+ component: CheckInCamera
},
{
path: 'stats',
- name: 'scannerStats',
- component: ScannedStats
+ name: 'checkInStats',
+ component: CheckInStats
}
]
}
diff --git a/src/stores/api.js b/src/stores/api.js
index 2c8b0b0..5b30146 100644
--- a/src/stores/api.js
+++ b/src/stores/api.js
@@ -2,9 +2,11 @@ import { defaults, mande } from 'mande'
import { defineStore } from 'pinia'
export const useApiStore = defineStore('api', () => {
- const apiUrl = import.meta.env.PROD
- ? import.meta.env.VITE_PROD_API_URL
- : import.meta.env.VITE_TEST_API_URL
+ const apiUrl =
+ import.meta.env.MODE === 'production'
+ ? import.meta.env.VITE_PROD_API_URL
+ : import.meta.env.VITE_TEST_API_URL
+
let instance = mande(apiUrl)
function setToken() {
diff --git a/src/stores/attendees.js b/src/stores/attendees.js
index e0743cc..29cc3b0 100644
--- a/src/stores/attendees.js
+++ b/src/stores/attendees.js
@@ -8,10 +8,9 @@ export const useAttendeesStore = defineStore('attendees', () => {
const apiStore = useApiStore()
const stations = useStationsStore()
const sessions = useSessionsStore()
-
const attendees = ref([])
- function clearAttendees() {
+ function $reset() {
attendees.value = []
}
@@ -69,25 +68,19 @@ export const useAttendeesStore = defineStore('attendees', () => {
}
}
- async function checkInAttendee(attendeeId, microlocationId) {
+ async function checkInAttendee(attendeeId, stationId, scannerType) {
try {
- const stationId = await stations.getStationIdWithMicrolocation(microlocationId)
- const session = await sessions.getCurrentSession(microlocationId)
- const sessionId = session ? String(session.id) : null
- const payload = {
+ const actualStationId = await stations.getActualStationId(stationId, scannerType)
+ if (!actualStationId) {
+ return Promise.reject('No station found.')
+ }
+ let payload = {
data: {
relationships: {
station: {
data: {
type: 'station',
- id: String(stationId)
- }
- },
- // session is optional if is daily check in
- session: {
- data: {
- type: 'session',
- id: sessionId
+ id: String(actualStationId)
}
},
ticket_holder: {
@@ -100,9 +93,23 @@ export const useAttendeesStore = defineStore('attendees', () => {
type: 'user_check_in'
}
}
- return await apiStore.post(true, 'user-check-in', payload, false)
+
+ if (scannerType !== 'daily') {
+ const session = await sessions.getCurrentSession(stationId)
+ const sessionId = session ? String(session.id) : null
+ payload.data.relationships.session = {
+ data: {
+ type: 'session',
+ id: String(sessionId)
+ }
+ }
+ }
+ return await apiStore.post(true, 'user-check-in', payload)
} catch (error) {
- return Promise.reject('Error checking in.')
+ if (error.response?.status === 422) {
+ return Promise.reject('already done')
+ }
+ return Promise.reject('Error processing.')
}
}
@@ -117,7 +124,7 @@ export const useAttendeesStore = defineStore('attendees', () => {
return {
attendees,
- clearAttendees,
+ $reset,
fetchAttendees,
registerAttendee,
checkInAttendee,
diff --git a/src/stores/auth.js b/src/stores/auth.js
index b46e0c4..3ee8212 100644
--- a/src/stores/auth.js
+++ b/src/stores/auth.js
@@ -1,4 +1,5 @@
import { useApiStore } from '@/stores/api'
+import clearStores from '@/utils/clearStores'
import { defineStore } from 'pinia'
export const useAuthStore = defineStore('auth', () => {
@@ -9,6 +10,8 @@ export const useAuthStore = defineStore('auth', () => {
const res = await apiStore.post(false, 'auth/logout')
useApiStore().clearToken()
localStorage.clear()
+ // clear all stores as well
+ clearStores()
return res.success
} catch (error) {
return Promise.reject(error)
diff --git a/src/stores/camera.js b/src/stores/camera.js
index 83162d8..3feab66 100644
--- a/src/stores/camera.js
+++ b/src/stores/camera.js
@@ -2,21 +2,48 @@ import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useCameraStore = defineStore('camera', () => {
- const cameraSide = ref('front')
- const QRCodeValue = ref('')
+ const selectedCameraId = ref({
+ deviceId: 'environment'
+ })
+ const cameraDevices = ref([])
+ const paused = ref(false)
+ const qrCodeValue = ref(null)
function $reset() {
- cameraSide.value = 'front'
- QRCodeValue.value = ''
+ selectedCameraId.value = {
+ deviceId: 'environment'
+ }
+ paused.value = false
+ cameraDevices.value = []
+ qrCodeValue.value = null
}
function toggleCameraSide() {
- cameraSide.value = cameraSide.value === 'front' ? 'back' : 'front'
+ // get length of devices
+ // if length is 1, then toggle is not possible
+ const qty = cameraDevices.value
+ if (qty === 1) {
+ return
+ }
+
+ let index = cameraDevices.value.findIndex((device) => {
+ return device.id === selectedCameraId.value.deviceId
+ })
+
+ // selected device is the next index
+ const nextIndex = index + 1
+ // if next index is the last index, then select the first index
+ if (nextIndex === cameraDevices.value.length) {
+ selectedCameraId.value.deviceId = cameraDevices.value[0].id
+ return
+ }
+ // else select the next index
+ selectedCameraId.value.deviceId = cameraDevices.value[nextIndex].id
}
function paintOutline(detectedCodes, ctx) {
for (const detectedCode of detectedCodes) {
- QRCodeValue.value = detectedCode.rawValue
+ qrCodeValue.value = detectedCode.rawValue
const [firstPoint, ...otherPoints] = detectedCode.cornerPoints
ctx.strokeStyle = 'red'
ctx.strokeWidth = 5
@@ -37,19 +64,18 @@ export const useCameraStore = defineStore('camera', () => {
value: paintOutline
}
- async function logErrors(promise) {
- try {
- await promise
- } catch (error) {
- if (error.name === 'OverconstrainedError') {
- camera.value = 'auto'
- }
+ function logErrors(error) {
+ console.error(error)
+ if (error.name === 'NotAllowedError') {
+ console.error('You need to grant this page permission to access your camera and microphone.')
}
}
return {
- cameraSide,
- QRCodeValue,
+ selectedCameraId,
+ paused,
+ cameraDevices,
+ qrCodeValue,
$reset,
toggleCameraSide,
selected,
diff --git a/src/stores/events.js b/src/stores/events.js
index f779331..2cb0347 100644
--- a/src/stores/events.js
+++ b/src/stores/events.js
@@ -8,6 +8,12 @@ export const useEventsStore = defineStore('events', () => {
const eventMicrolocations = ref([])
const eventName = ref('')
+ function $reset() {
+ userEvents.value = []
+ eventMicrolocations.value = []
+ eventName.value = ''
+ }
+
async function getEvents() {
try {
const res = await apiStore.get(true, 'users/user-details/get-user-id') // get user id
@@ -15,7 +21,7 @@ export const useEventsStore = defineStore('events', () => {
userEvents.value = []
// get user list of events
- const r = await apiStore.get(true, `users/${res.user_id}/events`)
+ const r = await apiStore.get(true, `users/${res.user_id}/events?sort=name&page[size]=1000`)
// remap data to new key
r.data.forEach((event) => {
@@ -31,7 +37,7 @@ export const useEventsStore = defineStore('events', () => {
async function getEventMicrolocations(eventId) {
try {
- const res = await apiStore.get(true, `events/${eventId}/microlocations`)
+ const res = await apiStore.get(true, `events/${eventId}/microlocations?page[size]=1000`)
// clear eventMicrolocations
eventMicrolocations.value = []
@@ -65,6 +71,7 @@ export const useEventsStore = defineStore('events', () => {
eventName,
userEvents,
eventMicrolocations,
+ $reset,
getEvents,
getEventMicrolocations,
getEventName
diff --git a/src/stores/navbar.js b/src/stores/navbar.js
index 1595a66..898ab57 100644
--- a/src/stores/navbar.js
+++ b/src/stores/navbar.js
@@ -8,7 +8,7 @@ import {
MagnifyingGlassIcon
} from '@heroicons/vue/24/outline'
import { defineStore } from 'pinia'
-import { computed } from 'vue'
+import { computed, onBeforeMount, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
export const useNavbarStore = defineStore('navbar', () => {
@@ -16,31 +16,56 @@ export const useNavbarStore = defineStore('navbar', () => {
const router = useRouter()
const eventsStore = useEventsStore()
const stationsStore = useStationsStore()
-
const passwordModalStore = usePasswordModalStore()
- const navbarTitle = computed(() => {
- // check if event id and station id exist in url params
+ // watch for router change and call fetchNavbarTitle
+ watch(
+ () => route.params,
+ async () => {
+ await fetchNavbarTitle()
+ }
+ )
+
+ onBeforeMount(async () => {
+ await router.isReady()
+ await fetchNavbarTitle()
+ })
+
+ const station = computed(() => {
+ const sn = stationsStore.eventStations.find(
+ // provide base for parse Int
+ (s) => s.id === parseInt(route.params.stationId, 10)
+ )
+ // if undefined return false
+ if (!sn) {
+ return false
+ }
+
+ return sn
+ })
+
+ async function fetchNavbarTitle() {
if (route.params.eventId && route.params.stationId) {
// check if event name is empty
if (!eventsStore.eventName) {
// event name empty so call for event name
- eventsStore.getEventName(route.params.eventId)
+ await eventsStore.getEventName(route.params.eventId)
}
- if (!stationsStore.eventStations.length > 0) {
- stationsStore.getStations(route.params.eventId)
+ if (!station.value || !stationsStore.eventStations.length > 0) {
+ await stationsStore.getStations(route.params.eventId)
}
- // find station name
- const station = stationsStore.eventStations.find(
- // provide base for parse Int
- (station) => station.id === parseInt(route.params.stationId, 10)
- )
- if (!station) {
+ }
+ }
+
+ const navbarTitle = computed(() => {
+ // check if event id and station id exist in url params
+ if (route.params.eventId && route.params.stationId) {
+ if (!station.value) {
return ''
}
- return `${eventsStore.eventName} - ${station.attributes['station-name']}`
+ return `${eventsStore.eventName} - ${station.value.attributes['station-name']}`
}
return ''
})
@@ -52,14 +77,14 @@ export const useNavbarStore = defineStore('navbar', () => {
// authenticated and not station page
const stationNavigation = computed(() => {
- if (route.name !== 'stationSelector') {
+ if (route.name !== 'selectStation') {
let obj = {
icon: MagnifyingGlassIcon,
name: 'Search',
customClass: 'text-body hover:bg-body-light',
action: () => {
if (route.params.registrationType) {
- router.push({ name: 'registerHybrid' })
+ router.push({ name: 'registerStation' })
}
}
}
@@ -74,7 +99,7 @@ export const useNavbarStore = defineStore('navbar', () => {
router.push({ name: 'registerKiosk' })
}
if (route.params.scannerType) {
- router.push({ name: 'scannerCamera' })
+ router.push({ name: 'checkInCamera' })
}
}
},
@@ -87,7 +112,7 @@ export const useNavbarStore = defineStore('navbar', () => {
router.push({ name: 'registerStats' })
}
if (route.params.scannerType) {
- router.push({ name: 'scannerStats' })
+ router.push({ name: 'checkInStats' })
}
}
}
diff --git a/src/stores/printModal.js b/src/stores/printModal.js
index 34887ed..3f362a0 100644
--- a/src/stores/printModal.js
+++ b/src/stores/printModal.js
@@ -18,13 +18,9 @@ export const usePrintModalStore = defineStore('printModal', () => {
const selectedOptions = ref([])
const hasOptions = computed(() => {
- return allOptions.value.length === 0
+ return allOptions.value.length !== 0
})
- function selectAll() {
- selectedOptions.value = printOptions.value
- }
-
function $reset() {
showPrintModal.value = false
printingText.value = false
@@ -54,12 +50,20 @@ export const usePrintModalStore = defineStore('printModal', () => {
}
}
+ function selectAll() {
+ selectedOptions.value = printOptions.value
+ }
+
async function setPrintDetails(tid, aid) {
loadingStore.contentLoading()
ticketId.value = String(tid)
attendeeId.value = String(aid)
- await getBadgeFields()
- loadingStore.contentLoaded()
+ try {
+ await getBadgeFields()
+ loadingStore.contentLoaded()
+ } catch (error) {
+ console.error(error)
+ }
nextTick(() => {
showPrintModal.value = true
})
@@ -76,8 +80,8 @@ export const usePrintModalStore = defineStore('printModal', () => {
// need to use URL from same domain to prevent origin error
let objFra = document.getElementById('printFrame')
- if (process.env.NODE_ENV !== 'development') {
- objFra.src = '/dist/test.pdf'
+ if (process.env.NODE_ENV !== 'production') {
+ objFra.src = '/test-badge.pdf'
} else {
const pdf = await apiStore.get(true, url.task_url.substring(4))
objFra.src = pdf.result.download_url
diff --git a/src/stores/processCheckIn.js b/src/stores/processCheckIn.js
index 2210115..c401b7f 100644
--- a/src/stores/processCheckIn.js
+++ b/src/stores/processCheckIn.js
@@ -1,9 +1,7 @@
import { useAttendeesStore } from '@/stores/attendees'
import { useCameraStore } from '@/stores/camera'
import { useLoadingStore } from '@/stores/loading'
-import { useTicketsStore } from '@/stores/tickets'
-import extractOrderId from '@/utils/extractOrderId'
-import isValidTicketQR from '@/utils/isValidTicketQR'
+import extractVcardID from '@/utils/extractVcardID'
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
@@ -11,7 +9,6 @@ export const useProcessCheckInStore = defineStore('processCheckIn', () => {
const loadingStore = useLoadingStore()
const cameraStore = useCameraStore()
const attendeesStore = useAttendeesStore()
- const ticketsStore = useTicketsStore()
const message = ref('')
const showSuccess = ref(false)
@@ -47,30 +44,37 @@ export const useProcessCheckInStore = defineStore('processCheckIn', () => {
showError.value = false
}
- async function checkInAttendeeScannerToRoom(microlocationId) {
- if (!isValidTicketQR(cameraStore.QRCodeValue)) {
+ async function checkInAttendeeScannerToRoom(microlocationId, scannerType) {
+ const attendeeId = extractVcardID(cameraStore.qrCodeValue)
+ if (!attendeeId) {
message.value = 'Invalid QR Code'
showErrorMsg()
return
}
- const orderId = extractOrderId(cameraStore.QRCodeValue)
loadingStore.contentLoading()
try {
- const attendee = await ticketsStore.getTicketAttendee(orderId)
- const checkedIn = await attendeesStore.checkInAttendee(attendee.id, microlocationId)
+ const checkedIn = await attendeesStore.checkInAttendee(
+ attendeeId,
+ microlocationId,
+ scannerType
+ )
if (checkedIn) {
- message.value = 'Checked in: ' + name
+ message.value = 'Attendee ' + attendeeId + ' scan success.'
showSuccessMsg()
} else {
- message.value = name + ' already checked in.'
+ message.value = 'Unknown error'
showErrorMsg()
}
loadingStore.contentLoaded()
} catch (error) {
+ if (error === 'already done') {
+ message.value = 'Attendee ' + attendeeId + ' already scanned.'
+ } else {
+ message.value = error
+ }
loadingStore.contentLoaded()
- message.value = error
showErrorMsg()
}
}
diff --git a/src/stores/processRegistration.js b/src/stores/processRegistration.js
index 2645f6d..03fc86a 100644
--- a/src/stores/processRegistration.js
+++ b/src/stores/processRegistration.js
@@ -4,6 +4,7 @@ import { useLoadingStore } from '@/stores/loading'
import { useNotificationStore } from '@/stores/notification'
import { usePrintModalStore } from '@/stores/printModal'
import { useTicketsStore } from '@/stores/tickets'
+import extractAttendeeId from '@/utils/extractAttendeeId'
import extractOrderId from '@/utils/extractOrderId'
import isValidTicketQR from '@/utils/isValidTicketQR'
import { defineStore } from 'pinia'
@@ -29,7 +30,7 @@ export const useProcessRegistrationStore = defineStore('processRegistration', ()
}
// end
} else {
- notificationStore.addNotification({ type: 'error', message: 'Already checked in' })
+ notificationStore.addNotification(['Error', 'Already checked in'], 'error')
}
} catch (error) {
console.log(error)
@@ -38,24 +39,23 @@ export const useProcessRegistrationStore = defineStore('processRegistration', ()
}
async function registerAttendeeScanner(stationId) {
- if (!isValidTicketQR(cameraStore.QRCodeValue)) {
- notificationStore.addNotification({ type: 'error', message: 'Invalid QR Code' })
+ if (!isValidTicketQR(cameraStore.qrCodeValue)) {
+ notificationStore.addNotification(['Error', 'Invalid QR Code'], 'error')
return
}
- const orderId = extractOrderId(cameraStore.QRCodeValue)
+ const attendeeId = extractAttendeeId(cameraStore.qrCodeValue)
+ const orderId = extractOrderId(cameraStore.qrCodeValue)
+
loadingStore.contentLoading()
try {
const attendee = await ticketsStore.getTicketAttendee(orderId)
- await processRegistrationCheckin(attendee.id, stationId)
- printModalStore.setPrintDetails(attendee.attributes['ticket-id'], attendee.id)
+ await processRegistrationCheckin(attendeeId, stationId)
+ printModalStore.setPrintDetails(attendee.attributes['ticket-id'], attendeeId)
} catch (error) {
console.log(error)
loadingStore.contentLoaded()
- notificationStore.addNotification({
- type: 'error',
- message: 'Unable to retrieve badge details'
- })
+ notificationStore.addNotification(['Error', 'Unable to retrieve badge details'], 'error')
}
}
diff --git a/src/stores/sessions.js b/src/stores/sessions.js
index 7aba800..550306f 100644
--- a/src/stores/sessions.js
+++ b/src/stores/sessions.js
@@ -11,6 +11,11 @@ export const useSessionsStore = defineStore('sessions', () => {
const sessions = ref([])
const currentSession = ref(null)
+ function $reset() {
+ sessions.value = []
+ currentSession.value = null
+ }
+
async function getSessions(eventId) {
try {
const res = await apiStore.get(true, `events/${eventId}/sessions`)
@@ -40,7 +45,7 @@ export const useSessionsStore = defineStore('sessions', () => {
if (currentSession.value) {
return currentSession.value.attributes['title']
}
- return 'No Session'
+ return 'No Session Name'
})
const currentSessionTimeRange = computed(() => {
@@ -55,7 +60,7 @@ export const useSessionsStore = defineStore('sessions', () => {
})
const formattedSessionDetails = computed(() => {
- if (currentSession.value === undefined) {
+ if (currentSession.value === null) {
return 'No Session'
}
@@ -66,5 +71,12 @@ export const useSessionsStore = defineStore('sessions', () => {
return str
})
- return { getSessions, getCurrentSession, currentSessionName, formattedSessionDetails }
+ return {
+ getSessions,
+ currentSession,
+ getCurrentSession,
+ $reset,
+ currentSessionName,
+ formattedSessionDetails
+ }
})
diff --git a/src/stores/stationSelector.js b/src/stores/stationSelector.js
index 74603fa..e4517eb 100644
--- a/src/stores/stationSelector.js
+++ b/src/stores/stationSelector.js
@@ -3,7 +3,7 @@ import { useStationsStore } from '@/stores/stations'
import { defineStore } from 'pinia'
import { computed, ref, watch } from 'vue'
-export const useStationSelectorStore = defineStore('stationSelector', () => {
+export const useStationSelectorStore = defineStore('selectStation', () => {
const eventsStore = useEventsStore()
const stationsStore = useStationsStore()
@@ -18,11 +18,6 @@ export const useStationSelectorStore = defineStore('stationSelector', () => {
href: ''
})
- const selectedMicrolocation = ref({
- id: null,
- name: ''
- })
-
const selectedStation = ref({
id: null,
name: ''
@@ -40,10 +35,6 @@ export const useStationSelectorStore = defineStore('stationSelector', () => {
name: '',
href: ''
}
- selectedMicrolocation.value = {
- id: null,
- name: ''
- }
selectedStation.value = {
id: null,
name: ''
@@ -55,7 +46,7 @@ export const useStationSelectorStore = defineStore('stationSelector', () => {
if (
selectedType.value.id === 'registration-kiosk' ||
selectedType.value.id === 'registration-hybrid' ||
- selectedType.value.id === 'check-in-daily'
+ selectedType.value.id === 'daily'
) {
return true
} else if (selectedType.value.id === 'check-in' || selectedType.value.id === 'checkout') {
@@ -70,7 +61,7 @@ export const useStationSelectorStore = defineStore('stationSelector', () => {
selectedStation.value.id == 'create-new' &&
(selectedType.value.id == 'registration-kiosk' ||
selectedType.value.id == 'registration-hybrid' ||
- selectedType.value.id == 'check-in-daily')
+ selectedType.value.id == 'daily')
)
})
@@ -80,18 +71,25 @@ export const useStationSelectorStore = defineStore('stationSelector', () => {
selectedType.value.id === 'registration-hybrid'
) {
return stationsStore.registrationStations
- } else if (selectedType.value.id === 'check-in-daily') {
+ } else if (selectedType.value.id === 'daily') {
return stationsStore.checkInDailyStations
} else {
return []
}
})
- const isRegistrationStations = computed(() => {
+ const isRegisterDailyStations = computed(() => {
return (
selectedType.value.id === 'registration-kiosk' ||
selectedType.value.id === 'registration-hybrid' ||
- selectedType.value.id === 'check-in-daily'
+ selectedType.value.id === 'daily'
+ )
+ })
+
+ const isRegisterStations = computed(() => {
+ return (
+ selectedType.value.id === 'registration-kiosk' ||
+ selectedType.value.id === 'registration-hybrid'
)
})
@@ -101,10 +99,10 @@ export const useStationSelectorStore = defineStore('stationSelector', () => {
}
if (selectedType.value.id === 'check-in' || selectedType.value.id === 'checkout') {
- return selectedMicrolocation.value.id !== null && selectedMicrolocation.value.id !== ''
+ return selectedStation.value.id !== null && selectedStation.value.id !== ''
}
- if (isRegistrationStations.value) {
+ if (isRegisterDailyStations.value) {
if (selectedStation.value.id === null) {
return false
}
@@ -128,10 +126,6 @@ export const useStationSelectorStore = defineStore('stationSelector', () => {
name: '',
href: ''
}
- selectedMicrolocation.value = {
- id: null,
- name: ''
- }
selectedStation.value = {
id: null,
name: ''
@@ -141,11 +135,6 @@ export const useStationSelectorStore = defineStore('stationSelector', () => {
})
watch(selectedType, async (newValue, oldValue) => {
- // type change so clear all fields after
- selectedMicrolocation.value = {
- id: null,
- name: ''
- }
if (oldValue) {
if (
(oldValue.id === 'registration-kiosk' || oldValue.id === 'registration-hybrid') &&
@@ -177,11 +166,11 @@ export const useStationSelectorStore = defineStore('stationSelector', () => {
return {
selectedEvent,
selectedType,
- selectedMicrolocation,
selectedStation,
newStationName,
isStationType,
- isRegistrationStations,
+ isRegisterDailyStations,
+ isRegisterStations,
isCreateNewStation,
availableStations,
validation,
diff --git a/src/stores/stations.js b/src/stores/stations.js
index 71887ea..545aa49 100644
--- a/src/stores/stations.js
+++ b/src/stores/stations.js
@@ -6,40 +6,72 @@ export const useStationsStore = defineStore('stations', () => {
const apiStore = useApiStore()
const stationTypes = [
- { id: 'registration-kiosk', name: 'Registration (via scan)', href: 'registerKiosk' },
- { id: 'registration-hybrid', name: 'Registration (hybrid)', href: 'registerHybrid' },
- { id: 'check-in-daily', name: 'Daily Check-In', href: 'scanner' },
- { id: 'check-in', name: 'Session Check-In', href: 'scanner' },
- { id: 'checkout', name: 'Session Checkout', href: 'scanner' }
+ {
+ id: 'registration-kiosk',
+ type: 'registration',
+ name: 'Registration Kiosk (with Scan only)',
+ href: 'registerKiosk'
+ },
+ {
+ id: 'registration-hybrid',
+ type: 'registration',
+ name: 'Registration Station (with Scan & Search)',
+ href: 'registerStation'
+ },
+ { id: 'daily', type: 'daily', name: 'Daily Check-In', href: 'checkIn' },
+ { id: 'check-in', type: 'check in', name: 'Session Check-In', href: 'checkIn' },
+ { id: 'checkout', type: 'check out', name: 'Session Checkout', href: 'checkIn' }
]
const actualEventStations = ref([])
const eventStations = ref([])
+ function $reset() {
+ actualEventStations.value = []
+ eventStations.value = []
+ }
+
async function getStations(eventId) {
try {
- const res = await apiStore.get(true, `events/${eventId}/stations`)
+ const res = await apiStore.get(true, `events/${eventId}/stations?page[size]=1000`)
actualEventStations.value = res.data
+ // clone data to remove reactivity
+ let data = JSON.parse(JSON.stringify(res.data))
+
// check for those with microlocation-id in attributes to replace id with microlocation-id
- res.data.forEach((station) => {
+ data.forEach((station) => {
if (station.attributes['microlocation-id']) {
station.id = station.attributes['microlocation-id']
}
})
- eventStations.value = res.data
+ eventStations.value = data
} catch (error) {
return Promise.reject(error)
}
}
- async function getStationIdWithMicrolocation(microlocationId) {
- // assuming index of actualEventStations is the same as eventStations
- // find index of station with microlocation-id
- const index = eventStations.value.findIndex((station) => {
- station.id === microlocationId
- })
- // get station id from actualEventStations
- return actualEventStations.value[index].id
+ async function getActualStationId(stationId, scannerType) {
+ let station = null
+ if (scannerType === 'check-in') {
+ station = checkInStations.value.find((s) => {
+ return s.microlocationId === Number(stationId)
+ })
+ } else if (scannerType === 'checkout') {
+ station = checkOutStations.value.find((s) => {
+ return s.microlocationId === Number(stationId)
+ })
+ } else {
+ // find station object in case spoofing via url
+ station = actualEventStations.value.find((s) => {
+ return s.id === Number(stationId)
+ })
+ }
+
+ if (station === null) {
+ return false
+ }
+
+ return station.id
}
async function createStation(payload) {
@@ -96,7 +128,7 @@ export const useStationsStore = defineStore('stations', () => {
})
const checkInStations = computed(() => {
- return eventStations.value
+ return actualEventStations.value
.filter((station) => {
return station.attributes['station-type'] === 'check in'
})
@@ -110,7 +142,7 @@ export const useStationsStore = defineStore('stations', () => {
})
const checkOutStations = computed(() => {
- return eventStations.value
+ return actualEventStations.value
.filter((station) => {
return station.attributes['station-type'] === 'check out'
})
@@ -125,13 +157,14 @@ export const useStationsStore = defineStore('stations', () => {
return {
eventStations,
+ $reset,
createStation,
registrationStations,
checkInDailyStations,
checkInStations,
checkOutStations,
getStations,
- getStationIdWithMicrolocation,
+ getActualStationId,
stationTypes
}
})
diff --git a/src/stores/user.js b/src/stores/user.js
index f639403..aa9d7bf 100644
--- a/src/stores/user.js
+++ b/src/stores/user.js
@@ -1,7 +1,14 @@
import { useApiStore } from '@/stores/api'
import { defineStore } from 'pinia'
+import { computed, ref } from 'vue'
export const useUserStore = defineStore('user', () => {
+ const userDetails = ref(null)
+
+ function $reset() {
+ userDetails.value = null
+ }
+
async function getUserId() {
try {
const res = await useApiStore().get(true, `users/user-details/get-user-id`)
@@ -13,12 +20,30 @@ export const useUserStore = defineStore('user', () => {
async function getUserDetails(userId) {
try {
- const res = await useApiStore().get(true, `users/${userId}`)
+ let id = ''
+ if (userId === undefined) {
+ id = await getUserId()
+ } else {
+ id = userId
+ }
+
+ const res = await useApiStore().get(true, `users/${id}`)
+ userDetails.value = res.data
return res
} catch (error) {
return Promise.reject(error)
}
}
- return { getUserId, getUserDetails }
+ const userName = computed(() => {
+ if (userDetails.value) {
+ const firstName = userDetails.value.attributes['first-name']
+ if (firstName !== null) {
+ return firstName
+ }
+ }
+ return ''
+ })
+
+ return { $reset, getUserId, getUserDetails, userName }
})
diff --git a/src/utils/clearStores.js b/src/utils/clearStores.js
new file mode 100644
index 0000000..a778f81
--- /dev/null
+++ b/src/utils/clearStores.js
@@ -0,0 +1,37 @@
+import { useAttendeesStore } from '@/stores/attendees'
+import { useCameraStore } from '@/stores/camera'
+import { useEventsStore } from '@/stores/events'
+import { usePasswordModalStore } from '@/stores/passwordModal'
+import { usePrintModalStore } from '@/stores/printModal'
+import { useProcessCheckInStore } from '@/stores/processCheckIn'
+import { useSessionsStore } from '@/stores/sessions'
+import { useStationsStore } from '@/stores/stations'
+import { useStationSelectorStore } from '@/stores/stationSelector'
+import { useTicketsStore } from '@/stores/tickets'
+import { useUserStore } from '@/stores/user'
+
+export default function clearStores() {
+ const attendeesStore = useAttendeesStore()
+ const cameraStore = useCameraStore()
+ const eventsStore = useEventsStore()
+ const passwordModalStore = usePasswordModalStore()
+ const printModalStore = usePrintModalStore()
+ const processCheckInStore = useProcessCheckInStore()
+ const sessionsStore = useSessionsStore()
+ const stationsStore = useStationsStore()
+ const stationSelectorStore = useStationSelectorStore()
+ const ticketsStore = useTicketsStore()
+ const userStore = useUserStore()
+
+ attendeesStore.$reset()
+ cameraStore.$reset()
+ eventsStore.$reset()
+ passwordModalStore.$reset()
+ printModalStore.$reset()
+ processCheckInStore.$reset()
+ sessionsStore.$reset()
+ stationsStore.$reset()
+ stationSelectorStore.$reset()
+ ticketsStore.$reset()
+ userStore.$reset()
+}
diff --git a/src/utils/extractAttendeeId.js b/src/utils/extractAttendeeId.js
new file mode 100644
index 0000000..fedc675
--- /dev/null
+++ b/src/utils/extractAttendeeId.js
@@ -0,0 +1,6 @@
+export default function extractAttendeeId(str) {
+ //remove last section of string from ticket id become attendee id
+ const regex = /(\d+)$/
+ const match = str.match(regex)
+ return match ? match[1] : null
+}
diff --git a/src/utils/extractVcardID.js b/src/utils/extractVcardID.js
new file mode 100644
index 0000000..30a0311
--- /dev/null
+++ b/src/utils/extractVcardID.js
@@ -0,0 +1,14 @@
+export default function extractVcardID(vcard) {
+ // check if EVENTYAY key exist in vcard
+ if (!vcard.includes('EVENTYAY')) {
+ return false
+ }
+ // split vcard into array
+ const vcardArray = vcard.split('\n')
+ // find the index of EVENTYAY key
+ const index = vcardArray.findIndex((item) => item.includes('EVENTYAY:'))
+ // get value from EVENTYAY key
+ const id = vcardArray[index].split(':')[1]
+
+ return id ? id : false
+}
diff --git a/src/utils/serverDateTimeToLocal.js b/src/utils/serverDateTimeToLocal.js
index 432a4c0..efded7b 100644
--- a/src/utils/serverDateTimeToLocal.js
+++ b/src/utils/serverDateTimeToLocal.js
@@ -4,5 +4,5 @@ import utc from 'dayjs/plugin/utc'
dayjs.extend(utc)
export default function serverDateTimeToLocal(serverDateTime) {
- return dayjs(serverDateTime).local().format('HH:mma')
+ return dayjs(serverDateTime).local().format('HH:mm')
}
diff --git a/src/views/ScannerTemplate.vue b/src/views/CheckInView.vue
similarity index 100%
rename from src/views/ScannerTemplate.vue
rename to src/views/CheckInView.vue
diff --git a/src/views/RegistrationStation.vue b/src/views/RegistrationView.vue
similarity index 100%
rename from src/views/RegistrationStation.vue
rename to src/views/RegistrationView.vue
diff --git a/src/views/StationSelector.vue b/src/views/SelectStation.vue
similarity index 100%
rename from src/views/StationSelector.vue
rename to src/views/SelectStation.vue