diff --git a/package-lock.json b/package-lock.json index 3e8b561..e14fefb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "mathjs": "^13.1.1", "mathml-to-latex": "^1.4.1", "npm": "^10.8.3", + "qrcode.react": "^4.1.0", "react": "^18.3.1", "react-beautiful-dnd": "^13.1.1", "react-dom": "^18.3.1", @@ -34,6 +35,7 @@ "react-icons": "^4.12.0", "react-katex": "^3.0.1", "react-leaflet": "^4.2.1", + "react-qr-code": "^2.0.15", "react-query": "^3.39.3", "react-router-dom": "^6.26.2", "react-toastify": "^9.1.3", @@ -12015,6 +12017,21 @@ } ] }, + "node_modules/qr.js": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz", + "integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==", + "license": "MIT" + }, + "node_modules/qrcode.react": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-4.1.0.tgz", + "integrity": "sha512-uqXVIIVD/IPgWLYxbOczCNAQw80XCM/LulYDADF+g2xDsPj5OoRwSWtIS4jGyp295wyjKstfG1qIv/I2/rNWpQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -12761,6 +12778,19 @@ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" }, + "node_modules/react-qr-code": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.15.tgz", + "integrity": "sha512-MkZcjEXqVKqXEIMVE0mbcGgDpkfSdd8zhuzXEl9QzYeNcw8Hq2oVIzDLWuZN2PQBwM5PWjc2S31K8Q1UbcFMfw==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.8.1", + "qr.js": "0.0.0" + }, + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-query": { "version": "3.39.3", "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz", @@ -23463,6 +23493,17 @@ "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "dev": true }, + "qr.js": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz", + "integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==" + }, + "qrcode.react": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-4.1.0.tgz", + "integrity": "sha512-uqXVIIVD/IPgWLYxbOczCNAQw80XCM/LulYDADF+g2xDsPj5OoRwSWtIS4jGyp295wyjKstfG1qIv/I2/rNWpQ==", + "requires": {} + }, "querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -23980,6 +24021,15 @@ } } }, + "react-qr-code": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.15.tgz", + "integrity": "sha512-MkZcjEXqVKqXEIMVE0mbcGgDpkfSdd8zhuzXEl9QzYeNcw8Hq2oVIzDLWuZN2PQBwM5PWjc2S31K8Q1UbcFMfw==", + "requires": { + "prop-types": "^15.8.1", + "qr.js": "0.0.0" + } + }, "react-query": { "version": "3.39.3", "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz", diff --git a/package.json b/package.json index b636ccd..1504d36 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "mathjs": "^13.1.1", "mathml-to-latex": "^1.4.1", "npm": "^10.8.3", + "qrcode.react": "^4.1.0", "react": "^18.3.1", "react-beautiful-dnd": "^13.1.1", "react-dom": "^18.3.1", @@ -29,6 +30,7 @@ "react-icons": "^4.12.0", "react-katex": "^3.0.1", "react-leaflet": "^4.2.1", + "react-qr-code": "^2.0.15", "react-query": "^3.39.3", "react-router-dom": "^6.26.2", "react-toastify": "^9.1.3", diff --git a/src/Components/Table/ActionButtons.tsx b/src/Components/Table/ActionButtons.tsx index ff70e3b..ce1fb95 100644 --- a/src/Components/Table/ActionButtons.tsx +++ b/src/Components/Table/ActionButtons.tsx @@ -5,6 +5,8 @@ import { RiDeleteBin6Fill } from "react-icons/ri"; import { useTranslation } from "react-i18next"; import { BsEyeFill } from "react-icons/bs"; import { GoTrash } from "react-icons/go"; +import { BsQrCode } from "react-icons/bs"; + interface ActionButtonsProps { canEdit?: boolean; @@ -17,9 +19,13 @@ interface ActionButtonsProps { onShow?: () => void; index?: number; className?: string; + canShowQr?:boolean + onShoqQr?: () => void; } const ActionButtons: React.FC = ({ + canShowQr, + onShoqQr, canEdit, canDelete, editTooltipTitle = "practical.edit", @@ -38,6 +44,10 @@ const ActionButtons: React.FC = ({ : "buttonAction"; return ( + {canShowQr && ( + + )} + {canEdit && ( @@ -54,7 +64,7 @@ const ActionButtons: React.FC = ({ {canShow && ( )} - + ); }; diff --git a/src/Components/Table/QRCodeGenerator.tsx b/src/Components/Table/QRCodeGenerator.tsx new file mode 100644 index 0000000..b2fd304 --- /dev/null +++ b/src/Components/Table/QRCodeGenerator.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import QRCode from 'react-qr-code'; + + +const QRCodeGenerator = ({url,serial}:any) => { +const qrValue = `${url}/${serial}` +console.log(qrValue) + return ( +
+ +
+ ); +}; + +export default QRCodeGenerator; diff --git a/src/Layout/Dashboard/QrCodeModels.tsx b/src/Layout/Dashboard/QrCodeModels.tsx new file mode 100644 index 0000000..72b1b48 --- /dev/null +++ b/src/Layout/Dashboard/QrCodeModels.tsx @@ -0,0 +1,52 @@ +import React from "react"; +import { Modal } from "antd"; +import { useModalState } from "../../zustand/Modal"; +import { useObjectToEdit } from "../../zustand/ObjectToEditState"; +import { useTranslation } from "react-i18next"; +import { MdCancel } from "react-icons/md"; +import QRCodeGenerator from "../../Components/Table/QRCodeGenerator"; + +interface ModalFormProps { + ModelEnum: any; + isNavigate?: boolean; + idVerify?: boolean; +} + +const QrCodeModels: React.FC = ({ + ModelEnum, + isNavigate = false, + idVerify = true, +}) => { + const { isOpen, setIsOpen } = useModalState((state) => state); + + const { objectToEdit, setObjectToEdit } = useObjectToEdit(); + + + const handleCancel = () => { + setIsOpen(""); + setObjectToEdit({}); + }; + + return ( + +
+ +
+ +
+
+ +
+
+
+ ); +}; + +export default QrCodeModels; diff --git a/src/Pages/Admin/question/Page.tsx b/src/Pages/Admin/question/Page.tsx index aba42b1..b3aeab6 100644 --- a/src/Pages/Admin/question/Page.tsx +++ b/src/Pages/Admin/question/Page.tsx @@ -17,6 +17,7 @@ import { canAddQuestion } from "../../../utils/hasAbilityFn"; import FilterLayout from "../../../Layout/Dashboard/FilterLayout"; import FilterForm from "./FilterForm"; import { useObjectToEdit } from "../../../zustand/ObjectToEditState"; +import QrCodeModels from "../../../Layout/Dashboard/QrCodeModels"; const Table = lazy(() => import("./Table")); const TableHeader = () => { @@ -82,6 +83,9 @@ const TableHeader = () => { deleteMutation={deleteMutation} ModelEnum={ModalEnum?.QUESTION_DELETE} /> + ); }; diff --git a/src/Pages/Admin/question/useTableColumns.tsx b/src/Pages/Admin/question/useTableColumns.tsx index 1c2e4bc..4d252be 100644 --- a/src/Pages/Admin/question/useTableColumns.tsx +++ b/src/Pages/Admin/question/useTableColumns.tsx @@ -33,6 +33,10 @@ export const useColumns = () => { setObjectToEdit(record); navigate(`${ABILITIES_ENUM?.QUESTION}/${record?.id}`); }; + const handleClickQr = (data:any)=>{ + setObjectToEdit(data); + setIsOpen(ModalEnum?.QUESTION_QR); + } const [t] = useTranslation(); const columns: TableColumnsType = [ @@ -113,6 +117,8 @@ export const useColumns = () => { index={index} onDelete={() => handelDelete(record)} onEdit={() => handleEdit(record)} + canShowQr={true} + onShoqQr={() =>handleClickQr(record)} /> ); }, diff --git a/src/enums/Model.ts b/src/enums/Model.ts index 6aa0ef6..8eb5b5f 100644 --- a/src/enums/Model.ts +++ b/src/enums/Model.ts @@ -151,6 +151,7 @@ export enum ModalEnum { ///// Question QUESTION_DELETE = "Question.delete", + QUESTION_QR = "Question.QrCode", QUESTION_ACCEPT = "Question.ACCEPT", ///Grade