From 83d4850cc618a42255d625ea3d6e8cfc3867c8c8 Mon Sep 17 00:00:00 2001 From: teegoood Date: Sat, 3 Aug 2024 09:09:36 +0700 Subject: [PATCH 1/5] fix: qrscanner send duplicate request --- src/components/rpkm/staff/home/qrscanner/QRScanner.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx b/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx index b12ad6d..a7914b7 100644 --- a/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx +++ b/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx @@ -8,6 +8,7 @@ import FailureModal from './failureModal'; import { createCheckIn } from '@/utils/checkin'; import { CheckIn } from '@/types/checkIn'; import { getCurrentTime } from '@/utils/time'; +import dayjs from 'dayjs'; const Scan: React.FC = () => { const [checkInData, setCheckInData] = useState(null); @@ -49,6 +50,7 @@ const Scan: React.FC = () => { //i don't useState because it not work with qrscanner const enable = localStorage.getItem('enable') === 'true'; if (!enable) return; + localStorage.setItem('enable', 'false'); const userId = scanRawData.text; const newCheckInData: CheckIn | null = await createCheckIn( @@ -57,10 +59,8 @@ const Scan: React.FC = () => { event ); - localStorage.setItem('enable', 'false'); - if (newCheckInData) { - /* if (newCheckInData.checkIn.isDuplicate) { + if (newCheckInData.checkIn.isDuplicate) { const date = dayjs(newCheckInData.checkIn.timestamp); setStatus('error'); setError( @@ -73,7 +73,7 @@ const Scan: React.FC = () => { setErrorTopic('Already taken!'); setTaken(true); return; - } */ + } setCheckInData(newCheckInData); setStatus('success'); From b4f64acc0215be8b14f0ae6159187fa28101a757 Mon Sep 17 00:00:00 2001 From: teegoood Date: Sat, 3 Aug 2024 09:30:17 +0700 Subject: [PATCH 2/5] lint fix --- src/components/rpkm/staff/home/qrscanner/QRScanner.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx b/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx index a7914b7..f152631 100644 --- a/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx +++ b/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx @@ -46,8 +46,8 @@ const Scan: React.FC = () => { event = 'rpkm-day-1'; } - //need to use localstorage to prevent user scan qr code multiple time - //i don't useState because it not work with qrscanner + //need to use localstorage to prevent user scaning multiple time + //don't use useState because it's not working with qrscanner const enable = localStorage.getItem('enable') === 'true'; if (!enable) return; localStorage.setItem('enable', 'false'); From c21b3ae5fb98f69f62c492522e67b8eb93761d8d Mon Sep 17 00:00:00 2001 From: teegoood Date: Sat, 3 Aug 2024 18:02:16 +0700 Subject: [PATCH 3/5] add: text input --- src/app/rpkm/staff/home/page.tsx | 115 ++++++++++++++-- .../rpkm/staff/home/qrscanner/QRScanner.tsx | 126 +++--------------- .../staff/home/qrscanner/StudentCodeInput.tsx | 54 ++++++++ src/utils/date.ts | 11 ++ 4 files changed, 183 insertions(+), 123 deletions(-) create mode 100644 src/components/rpkm/staff/home/qrscanner/StudentCodeInput.tsx create mode 100644 src/utils/date.ts diff --git a/src/app/rpkm/staff/home/page.tsx b/src/app/rpkm/staff/home/page.tsx index bf85490..ae215d7 100644 --- a/src/app/rpkm/staff/home/page.tsx +++ b/src/app/rpkm/staff/home/page.tsx @@ -1,38 +1,108 @@ 'use client'; + import Navbar from '@/components/rpkm/Navbar'; import Scan from '@/components/rpkm/staff/home/qrscanner/QRScanner'; +import { useAuth } from '@/context/AuthContext'; +import { createCheckIn } from '@/utils/checkin'; import { getCurrentTime } from '@/utils/time'; import React, { useEffect, useState } from 'react'; +import FailureModal from '@/components/rpkm/staff/home/qrscanner/failureModal'; +import ConfirmationModal from '@/components/rpkm/staff/home/qrscanner/confirmationModal'; +import { CheckIn } from '@/types/checkIn'; +import { FRESHYNIGHT_EVENT, RPKM_DAY_1, RPKM_DAY_2 } from '@/utils/date'; +import dayjs from 'dayjs'; +import StudentCodeInput from '@/components/rpkm/staff/home/qrscanner/StudentCodeInput'; function Page() { const [eventText, setEventText] = useState(''); + const { user } = useAuth(); + + //modal state + const [status, setStatus] = useState<'success' | 'error' | 'idle'>('idle'); + const [taken, setTaken] = useState(false); + const [error, setError] = useState(''); + const [errorTopic, setErrorTopic] = useState(''); + const [checkInData, setCheckInData] = useState(null); useEffect(() => { const initialize = async () => { const currentTime = (await getCurrentTime()).currentTime; - const freshy_night_time = new Date( - process.env.NEXT_PUBLIC_FRESHY_NIGHT_EVENT as string - ); - const rpkm_day_1_time = new Date( - process.env.NEXT_PUBLIC_RPKM_DAY_1 as string - ); - const rpkm_day_2_time = new Date( - process.env.NEXT_PUBLIC_RPKM_DAY_2 as string - ); - - if (currentTime >= freshy_night_time) { + if (currentTime >= FRESHYNIGHT_EVENT) { setEventText('Freshy Night'); - } else if (currentTime >= rpkm_day_2_time) { + } else if (currentTime >= RPKM_DAY_1) { setEventText('Onsite 4 สิงหาคม 2567'); - } else if (currentTime >= rpkm_day_1_time) { + } else if (currentTime >= RPKM_DAY_2) { setEventText('Onsite 3 สิงหาคม 2567'); } }; initialize(); + localStorage.setItem('enable', 'true'); }, []); + const handleCloseModal = () => { + setStatus('idle'); + localStorage.setItem('enable', 'true'); + }; + + const sendCheckInRequest = async (userId: string) => { + if (!userId || !user || localStorage.getItem('enable') !== 'true') { + return; + } + + //need to use localstorage to prevent user scaning multiple time + //don't use useState because it's not working with qrscanner + localStorage.setItem('enable', 'false'); + + let event = ''; + const currentTime = (await getCurrentTime()).currentTime; + + //need to check date every time because qr component don't update function when function re-render + if (currentTime >= FRESHYNIGHT_EVENT) { + event = 'freshy-night'; + } else if (currentTime >= RPKM_DAY_2) { + event = 'rpkm-day-2'; + } else if (currentTime >= RPKM_DAY_1) { + event = 'rpkm-day-1'; + } else { + console.log('invalid date'); + localStorage.setItem('enable', 'true'); + return; + } + + const newCheckInData: CheckIn | null = await createCheckIn( + userId, + user.email, + event + ); + + if (newCheckInData) { + if (newCheckInData.checkIn.isDuplicate) { + const date = dayjs(newCheckInData.checkIn.timestamp); + setStatus('error'); + setError( +
+ ผู้ใช้สแกน QR-code นี้แล้ว +
+ {`เมื่อเวลา ${date.format('HH:mm')} น.`} +
+ ); + setErrorTopic('Already taken!'); + setTaken(true); + return; + } + + setCheckInData(newCheckInData); + setStatus('success'); + } else { + setStatus('error'); + setError('แสกนไม่สำเร็จ โปรดลองอีกครั้ง'); + setErrorTopic('Invalid QR-code'); + setTaken(false); + } + }; + return (
@@ -63,13 +133,30 @@ function Page() {
{eventText}
+ +
หรือ
- +
QR-Reader
+ + + + ); } diff --git a/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx b/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx index f152631..b47704b 100644 --- a/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx +++ b/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx @@ -1,133 +1,41 @@ 'use client'; -import React, { ReactNode, useEffect, useState } from 'react'; +import React from 'react'; import { QrReader } from 'react-qr-reader'; import { motion } from 'framer-motion'; -import { useAuth } from '@/context/AuthContext'; -import ConfirmationModal from './confirmationModal'; -import FailureModal from './failureModal'; -import { createCheckIn } from '@/utils/checkin'; -import { CheckIn } from '@/types/checkIn'; -import { getCurrentTime } from '@/utils/time'; -import dayjs from 'dayjs'; -const Scan: React.FC = () => { - const [checkInData, setCheckInData] = useState(null); - const [taken, setTaken] = useState(false); - const [status, setStatus] = useState<'success' | 'error' | 'idle'>('idle'); - const { user } = useAuth(); - const [error, setError] = useState(''); - const [errorTopic, setErrorTopic] = useState(''); +interface ScanProps { + sendCheckInRequest: (userId: string) => Promise; +} +const Scan = ({ sendCheckInRequest }: ScanProps) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any - const handleScanResult = async (scanRawData: any) => { - if (!scanRawData || !user) { + const handleScanResult = (scanRawData: any) => { + if (!scanRawData) { return; } - - let event = ''; - const currentTime = (await getCurrentTime()).currentTime; - - //need to check date every time because qr component don't update function when function re-render - const freshy_night_time = new Date( - process.env.NEXT_PUBLIC_FRESHY_NIGHT_EVENT as string - ); - const rpkm_day_1_time = new Date( - process.env.NEXT_PUBLIC_RPKM_DAY_1 as string - ); - const rpkm_day_2_time = new Date( - process.env.NEXT_PUBLIC_RPKM_DAY_2 as string - ); - - if (currentTime > freshy_night_time) { - event = 'freshy-night'; - } else if (currentTime > rpkm_day_2_time) { - event = 'rpkm-day-2'; - } else if (currentTime > rpkm_day_1_time) { - event = 'rpkm-day-1'; - } - - //need to use localstorage to prevent user scaning multiple time - //don't use useState because it's not working with qrscanner - const enable = localStorage.getItem('enable') === 'true'; - if (!enable) return; - localStorage.setItem('enable', 'false'); - - const userId = scanRawData.text; - const newCheckInData: CheckIn | null = await createCheckIn( - userId, - user.email, - event - ); - - if (newCheckInData) { - if (newCheckInData.checkIn.isDuplicate) { - const date = dayjs(newCheckInData.checkIn.timestamp); - setStatus('error'); - setError( -
- ผู้ใช้สแกน QR-code นี้แล้ว -
- {`เมื่อเวลา ${date.format('HH:mm')} น.`} -
- ); - setErrorTopic('Already taken!'); - setTaken(true); - return; - } - - setCheckInData(newCheckInData); - setStatus('success'); - } else { - setStatus('error'); - setError('แสกนไม่สำเร็จ โปรดลองอีกครั้ง'); - setErrorTopic('Invalid QR-code'); - setTaken(false); - } + sendCheckInRequest(scanRawData.text); }; - const handleCloseModal = () => { - setStatus('idle'); - }; - - useEffect(() => { - localStorage.setItem('enable', 'true'); - }, []); - return (
- +
+ +
- - - - - {status == 'idle' && ( -

Please scan a QR code

- )} +

Please scan a QR code

diff --git a/src/components/rpkm/staff/home/qrscanner/StudentCodeInput.tsx b/src/components/rpkm/staff/home/qrscanner/StudentCodeInput.tsx new file mode 100644 index 0000000..33096e8 --- /dev/null +++ b/src/components/rpkm/staff/home/qrscanner/StudentCodeInput.tsx @@ -0,0 +1,54 @@ +import React, { useState } from 'react'; +import toast from 'react-hot-toast'; + +interface StudentCodeInputProps { + sendCheckInRequest: (userId: string) => Promise; +} + +const StudentCodeInput = ({ sendCheckInRequest }: StudentCodeInputProps) => { + const [studentCode, setStudentCode] = useState(''); + + const handleOnCheckIn = async () => { + if (studentCode.length !== 10) { + toast.error('กรุณากรอกรหัสนิสิตให้ครบ 10 หลัก'); + return; + } + + console.log(studentCode); + + // if (!user) { + // return; + // } + + await sendCheckInRequest('123'); + }; + + const handleOnChange = (e: React.ChangeEvent) => { + const value = e.target.value; + if (!'0123456789'.includes(value.at(-1) || '') || value.length > 10) { + return; + } + setStudentCode(value); + }; + + return ( +
+
กรอกรหัสนิสิต
+ + +
+ ); +}; + +export default StudentCodeInput; diff --git a/src/utils/date.ts b/src/utils/date.ts new file mode 100644 index 0000000..8a4c400 --- /dev/null +++ b/src/utils/date.ts @@ -0,0 +1,11 @@ +export const FRESHYNIGHT_EVENT = new Date( + process.env.NEXT_PUBLIC_FRESHY_NIGHT_EVENT as string +); + +export const RPKM_DAY_1 = new Date( + process.env.NEXT_PUBLIC_RPKM_DAY_1 as string +); + +export const RPKM_DAY_2 = new Date( + process.env.NEXT_PUBLIC_RPKM_DAY_2 as string +); From 2fdf30501398b83cc7836a7cbeb09e4eb0797c69 Mon Sep 17 00:00:00 2001 From: teegoood Date: Sat, 3 Aug 2024 18:39:28 +0700 Subject: [PATCH 4/5] add: post checkin by studentId --- src/app/rpkm/staff/home/page.tsx | 18 ++++++----- .../rpkm/staff/home/qrscanner/QRScanner.tsx | 9 ++++-- .../staff/home/qrscanner/StudentCodeInput.tsx | 22 ++++++------- src/utils/checkin.ts | 31 +++++++++++++++++++ 4 files changed, 57 insertions(+), 23 deletions(-) diff --git a/src/app/rpkm/staff/home/page.tsx b/src/app/rpkm/staff/home/page.tsx index ae215d7..951891b 100644 --- a/src/app/rpkm/staff/home/page.tsx +++ b/src/app/rpkm/staff/home/page.tsx @@ -3,7 +3,7 @@ import Navbar from '@/components/rpkm/Navbar'; import Scan from '@/components/rpkm/staff/home/qrscanner/QRScanner'; import { useAuth } from '@/context/AuthContext'; -import { createCheckIn } from '@/utils/checkin'; +import { createCheckIn, createCheckInByStudentId } from '@/utils/checkin'; import { getCurrentTime } from '@/utils/time'; import React, { useEffect, useState } from 'react'; import FailureModal from '@/components/rpkm/staff/home/qrscanner/failureModal'; @@ -46,8 +46,11 @@ function Page() { localStorage.setItem('enable', 'true'); }; - const sendCheckInRequest = async (userId: string) => { - if (!userId || !user || localStorage.getItem('enable') !== 'true') { + const sendCheckInRequest = async ( + mode: 'userId' | 'studentId', + id: string + ) => { + if (!user || localStorage.getItem('enable') !== 'true') { return; } @@ -71,11 +74,10 @@ function Page() { return; } - const newCheckInData: CheckIn | null = await createCheckIn( - userId, - user.email, - event - ); + const newCheckInData: CheckIn | null = + mode == 'userId' + ? await createCheckIn(id, user.email, event) + : await createCheckInByStudentId(id, user.email, event); if (newCheckInData) { if (newCheckInData.checkIn.isDuplicate) { diff --git a/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx b/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx index b47704b..85e8639 100644 --- a/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx +++ b/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx @@ -4,16 +4,19 @@ import { QrReader } from 'react-qr-reader'; import { motion } from 'framer-motion'; interface ScanProps { - sendCheckInRequest: (userId: string) => Promise; + sendCheckInRequest: ( + mode: 'userId' | 'studentId', + id: string + ) => Promise; } const Scan = ({ sendCheckInRequest }: ScanProps) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const handleScanResult = (scanRawData: any) => { - if (!scanRawData) { + if (!scanRawData || !scanRawData.text) { return; } - sendCheckInRequest(scanRawData.text); + sendCheckInRequest('userId', scanRawData.text); }; return ( diff --git a/src/components/rpkm/staff/home/qrscanner/StudentCodeInput.tsx b/src/components/rpkm/staff/home/qrscanner/StudentCodeInput.tsx index 33096e8..5e6c15c 100644 --- a/src/components/rpkm/staff/home/qrscanner/StudentCodeInput.tsx +++ b/src/components/rpkm/staff/home/qrscanner/StudentCodeInput.tsx @@ -2,25 +2,23 @@ import React, { useState } from 'react'; import toast from 'react-hot-toast'; interface StudentCodeInputProps { - sendCheckInRequest: (userId: string) => Promise; + sendCheckInRequest: ( + mode: 'userId' | 'studentId', + id: string + ) => Promise; } const StudentCodeInput = ({ sendCheckInRequest }: StudentCodeInputProps) => { - const [studentCode, setStudentCode] = useState(''); + const [studentId, setStudentId] = useState(''); const handleOnCheckIn = async () => { - if (studentCode.length !== 10) { + if (studentId.length !== 10) { toast.error('กรุณากรอกรหัสนิสิตให้ครบ 10 หลัก'); return; } - console.log(studentCode); - - // if (!user) { - // return; - // } - - await sendCheckInRequest('123'); + console.log(studentId); + await sendCheckInRequest('studentId', studentId); }; const handleOnChange = (e: React.ChangeEvent) => { @@ -28,7 +26,7 @@ const StudentCodeInput = ({ sendCheckInRequest }: StudentCodeInputProps) => { if (!'0123456789'.includes(value.at(-1) || '') || value.length > 10) { return; } - setStudentCode(value); + setStudentId(value); }; return ( @@ -37,7 +35,7 @@ const StudentCodeInput = ({ sendCheckInRequest }: StudentCodeInputProps) => { diff --git a/src/utils/checkin.ts b/src/utils/checkin.ts index 222e826..2f5bb8d 100644 --- a/src/utils/checkin.ts +++ b/src/utils/checkin.ts @@ -39,6 +39,37 @@ export const createCheckIn = async ( } }; +export const createCheckInByStudentId = async ( + studentId: string, + email: string, + event: string +): Promise => { + const accessToken = await getAccessToken(); + + if (!accessToken) { + return null; + } + + try { + const res: AxiosResponse = await apiClient.post( + `/checkin`, + { + email: email, + event: event, + student_id: studentId, + }, + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + } + ); + return CheckInParser(res.data); + } catch (error) { + return null; + } +}; + export const fetchCheckIn = async (): Promise => { const accessToken = await getAccessToken(); const userId = await getUserId(); From 42e637175d63759608ac6d92d21a9c6db06805ab Mon Sep 17 00:00:00 2001 From: teegoood Date: Sat, 3 Aug 2024 18:59:54 +0700 Subject: [PATCH 5/5] remove: scan delay --- src/components/rpkm/staff/home/qrscanner/QRScanner.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx b/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx index 85e8639..32668e7 100644 --- a/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx +++ b/src/components/rpkm/staff/home/qrscanner/QRScanner.tsx @@ -24,6 +24,7 @@ const Scan = ({ sendCheckInRequest }: ScanProps) => {