Skip to content

Commit

Permalink
Fix fossasia#63 implemented API for session check in (fossasia#77)
Browse files Browse the repository at this point in the history
* Add Home, Room Check-in

* fixed codacy

* clear netlify build

* Update SearchAttendee.vue

* Update ScanSearch

* Fixed navabr

* Update BaseTemplate.vue

* Removed bottom navbar and updated dropdown menu

* Minor fixes

* Added checklist to printModal and simplified router

* Name changes

* Fixed passwordModal and removed password requirement for stats

* Switched to template refs

* minor fixes

* Rearranged and renamed

* Fix codacy issues

* Changed casing

* Fix fossasia#31 Added dropdown list that allows user to choose which details to show on search

* Fixed format

* Fix codacy

* Minor fixes and renaming

* Minor fixes and moved some code to inline

* Fix fossasia#41 and codacy

* fix codacy

* Simplified code

* fix fossasia#48 created standard button component and replaced some buttons

* fix format

* Converted all buttons to standard component

* fixed format

* fix codacy

* Fix fossasia#40 standardised all p-6 except pages with scanners, optimised search function for mobile

* changed prop name

* removed activated classes

* Minor UI fixes

* fix fossasia#52 clicking print on search attendee now opens the print modal and logs name of card

* fix fossasia#51 new layout for print modal

* changed to margin

* removed grow flex

* minor fixes

* fix fossasia#50 created success notification that shows on print

* fix tailwind config

* removed redundant code

* fix  margin of print modal

* changed naming

* switched to camel case, moved some functions to inline

* added print modal store

* minor changes

* changed some refs to computed

* fix fossasia#49 fossasia#46 ported everything to stores

* fix codacy

* fix fossasia#59 fossasia#53 search and logout attached to respective APIs

* fix netlify

* fix netlify

* fix netlify

* fix codacy

* fix codacy

* fix codacy

* fix build

* fix codacy

* fix codacy

* fix fossasia#61 implemented API for checking in attendees in registration via scan or search

* fixed error

* added dayjs

* remove moment

* port to store

* fix comments

* fix comments

* fix comment

* fix fossasia#68 implemented better error handling for logout function

* Update auth.js

* Update auth.js

* fix fossasia#73 navbar dropdown fixed for small screen

* fix comment

* fix fossasia#63 implemented api for session check in

* minor fix

* minor fix

* Update tailwind.config.cjs

---------

Co-authored-by: cweitat <[email protected]>
Co-authored-by: lizardon <[email protected]>
  • Loading branch information
3 people committed Aug 4, 2023
1 parent 04bf7ea commit 439fe18
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 78 deletions.
82 changes: 27 additions & 55 deletions src/components/QRScanner/ScannerCamera.vue
Original file line number Diff line number Diff line change
@@ -1,66 +1,32 @@
<script setup>
import { QrcodeStream } from 'vue-qrcode-reader'
import { ref } from 'vue'
import { computed, ref } from 'vue'
import { useRoute } from 'vue-router'
import { ArrowsRightLeftIcon } from '@heroicons/vue/20/solid'
import StandardButton from '@/components/Shared/StandardButton.vue'
import { useQRScannerStore } from '@/stores/qrScanner'
import { useTypeSelectorStore } from '@/stores/typeSelector'
const qrScannerStore = useQRScannerStore()
const typeSelectorStore = useTypeSelectorStore()
// get scanner type from vue router params
const route = useRoute()
const scannerType = route.params.scannerType
const stationId = route.params.stationId
const eventId = route.params.eventId
const camera = ref('front')
const QRCodeValue = ref('')
const showNotification = ref(false)
const componentKey = ref(0)
const paintOutline = (detectedCodes, ctx) => {
for (const detectedCode of detectedCodes) {
QRCodeValue.value = detectedCode.rawValue
const [firstPoint, ...otherPoints] = detectedCode.cornerPoints
ctx.strokeStyle = 'red'
ctx.strokeWidth = 5
ctx.beginPath()
ctx.moveTo(firstPoint.x, firstPoint.y)
for (const { x, y } of otherPoints) {
ctx.lineTo(x, y)
}
ctx.lineTo(firstPoint.x, firstPoint.y)
ctx.closePath()
ctx.stroke()
}
}
const selected = {
text: 'outline',
value: paintOutline
}
const validQRCode = ref(true)
const decode = () => {
// check if QRCodeValue is valid and conforms to what is needed over here
console.log(QRCodeValue)
}
const showMessage = ref(false)
const refreshComponent = () => {
componentKey.value += 1
}
const updateShowNotification = (value) => {
showNotification.value = value
}
const fireFunction = () => {
// print user pass here
console.log('Printing...')
}
const switchCamera = () => {
camera.value = camera.value === 'front' ? 'rear' : 'front'
refreshComponent()
}
const stationName = computed(() => {
const station = typeSelectorStore.eventStations.find(
(station) => station.id === parseInt(stationId)
)
return station.attributes['station-name']
})
async function logErrors(promise) {
try {
Expand All @@ -82,24 +48,30 @@ async function logErrors(promise) {
<div class="w-full items-center flex justify-center">
<div>
<qrcode-stream
:key="componentKey"
class="!aspect-square !h-auto max-w-lg grid-cols-1 align-middle justify-center items-center"
:track="selected.value"
:track="qrScannerStore.selected.value"
:camera="camera"
@init="logErrors"
@decode="decode"
@decode="
async () => {
showMessage = await qrScannerStore.checkInAttendeeScannerToRoom(stationId, eventId)
}
"
>
</qrcode-stream>
<StandardButton
text="Switch Camera"
:icon="ArrowsRightLeftIcon"
class="bg-blue-600 text-white hover:bg-blue-500 mt-4"
@click="switchCamera"
@click="camera = camera === 'front' ? 'rear' : 'front'"
/>
</div>
</div>
<div v-if="QRCodeValue != ''" class="text-green-500 font-bold mt-5 text-lg text-center">
{ user name } has been checked into { room name }
<div v-if="showMessage" class="text-green-500 font-bold mt-5 text-lg text-center">
{{ qrScannerStore.name }} has been checked into {{ stationName }}
</div>
<div v-else class="text-red-500 font-bold mt-5 text-lg text-center">
{{ qrScannerStore.errorString }}
</div>
</div>
</template>
1 change: 0 additions & 1 deletion src/components/TypeSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ async function createStation(payload) {
}
async function submitForm() {
localStorage.setItem('event_id', selectedEvent.value.id)
loadingStore.show = true
if (
selectedType.value.id === 'registration-kiosk' ||
Expand Down
45 changes: 23 additions & 22 deletions src/stores/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,31 +39,32 @@ export const useApiStore = defineStore('api', () => {

async function post(requiresAuth, path, payload, hasBody) {
newSession(requiresAuth)
if (hasBody) {
delete defaults.headers['Content-Type']
const options = instance.options
options['body'] = payload
try {
return await instance.post(path)
} catch (error) {
return await Promise.reject(error)
}
} else {
if (payload) {
instance.options.headers['Accept'] = 'application/vnd.api+json'
instance.options.headers['Content-Type'] = 'application/vnd.api+json'
try {
return await instance.post(path, payload)
} catch (error) {
return await Promise.reject(error)
}
try {
if (hasBody) {
delete defaults.headers['Content-Type']
const options = instance.options
options['body'] = payload
const response = await instance.post(path)
return response
} else {
try {
return await instance.post(path)
} catch (error) {
return await Promise.reject(error)
if (payload) {
instance.options.headers['Accept'] = 'application/vnd.api+json'
instance.options.headers['Content-Type'] = 'application/vnd.api+json'
const response = await instance.post(path, payload)
return response
} else {
const response = await instance.post(path)
return response
}
}
} catch (error) {
const customError = {
message: 'An error occurred during the POST request',
status: error.response ? error.response.status : null,
data: error.response ? error.response.data : null,
originalError: error
}
return Promise.reject(customError)
}
}

Expand Down
116 changes: 116 additions & 0 deletions src/stores/qrScanner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { ref } from 'vue'
import { defineStore } from 'pinia'
import { useApiStore } from '@/stores/api'
import { useScannerStore } from '@/stores/scanner'

export const useQRScannerStore = defineStore('qrScanner', () => {
const QRCodeValue = ref('')
const name = ref('')
const errorString = ref('')

const paintOutline = (detectedCodes, ctx) => {
for (const detectedCode of detectedCodes) {
QRCodeValue.value = detectedCode.rawValue
const [firstPoint, ...otherPoints] = detectedCode.cornerPoints
ctx.strokeStyle = 'red'
ctx.strokeWidth = 5

ctx.beginPath()
ctx.moveTo(firstPoint.x, firstPoint.y)
for (const { x, y } of otherPoints) {
ctx.lineTo(x, y)
}
ctx.lineTo(firstPoint.x, firstPoint.y)
ctx.closePath()
ctx.stroke()
}
}

const selected = {
text: 'outline',
value: paintOutline
}

async function checkInAttendeeToRoom(attendeeId, stationId, eventId) {
try {
const stations = await useApiStore().get(true, `events/${eventId}/stations`)
const sessions = await useApiStore().get(true, `events/${eventId}/sessions`)
const station = stations.data.find((station) => station.id == stationId)
const payload = {
data: {
relationships: {
station: {
data: {
type: station.type,
id: stationId + ''
}
},
session: {
data: {
type: sessions.data[0].type,
id: sessions.data[0].id + ''
}
},
ticket_holder: {
data: {
type: 'attendee',
id: attendeeId + ''
}
}
},
type: 'user_check_in'
}
}
const checkInRes = await useApiStore().post(true, 'user-check-in', payload, false)
console.log('check in success to room:', checkInRes)
name.value = await getAttendeeName(attendeeId) // assign attendee name
} catch (error) {
const errors = error.originalError.body.errors
if (errors.find((error) => error.detail === 'Attendee already checked in.')) {
errorString.value = (await getAttendeeName(attendeeId)) + ' already checked in' // set error message to show user
setTimeout(() => (errorString.value = ''), 3000)
throw new Error('Already checked in')
}
}
}

async function checkInAttendeeScannerToRoom(stationId, eventId) {
if (useScannerStore().isValidQRCode(useScannerStore().stringModifier(QRCodeValue.value))) {
try {
await checkInAttendeeToRoom(
useScannerStore().extractId(QRCodeValue.value),
stationId,
eventId
)
return true
} catch (error) {
console.error(error)
return false
}
} else {
errorString.value = 'Invalid QR code'
setTimeout(() => (errorString.value = ''), 3000)
return false
}
}

async function getAttendeeName(attendeeId) {
try {
const attendee = await useApiStore().get(true, `attendees/${attendeeId}`)
return attendee.data.attributes['firstname'] + ' ' + attendee.data.attributes['lastname']
} catch (error) {
console.error(error)
return 'Attendee ' + attendeeId
}
}

return {
QRCodeValue,
name,
errorString,
selected,
paintOutline,
checkInAttendeeToRoom,
checkInAttendeeScannerToRoom
}
})
6 changes: 6 additions & 0 deletions tailwind.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** @type {import('tailwindcss').Config} */

module.exports = {
content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
plugins: [require('@tailwindcss/forms')]
}

0 comments on commit 439fe18

Please sign in to comment.