From f65c6293bdf7061abf2c729ff3733494d69d7c3a Mon Sep 17 00:00:00 2001 From: Akshata Katwal Date: Wed, 24 Jul 2024 18:24:46 +0530 Subject: [PATCH] Issue #PS-1471 feat : setup rjsf library, and integrate getFormRead fields --- package-lock.json | 285 ++++++++++++++++++++++- package.json | 7 +- public/locales/en/common.json | 64 ++++- src/components/AddLeanerModal.tsx | 184 +++++++++++++++ src/components/CustomRadioWidget.tsx | 50 ++++ src/components/DynamicForm.tsx | 151 ++++++++++++ src/components/GeneratedSchemas.ts | 214 +++++++++++++++++ src/components/HeaderComponent.tsx | 5 +- src/components/MultiSelectCheckboxes.tsx | 78 +++++++ src/components/SimpleModal.tsx | 156 +++++++++++++ src/components/UserTable.tsx | 11 +- src/components/form/NumberInputField.tsx | 52 +++++ src/pages/faciliator.tsx | 5 +- src/pages/learners.tsx | 17 +- src/pages/teamLeader.tsx | 5 +- src/services/CreateUserService.ts | 37 +++ src/store/manageUserStore.js | 35 +++ src/store/store.js | 22 ++ src/utils/Helper.ts | 16 +- src/utils/Interfaces.ts | 53 +++++ src/utils/app.constant.ts | 18 ++ 21 files changed, 1450 insertions(+), 15 deletions(-) create mode 100644 src/components/AddLeanerModal.tsx create mode 100644 src/components/CustomRadioWidget.tsx create mode 100644 src/components/DynamicForm.tsx create mode 100644 src/components/GeneratedSchemas.ts create mode 100644 src/components/MultiSelectCheckboxes.tsx create mode 100644 src/components/SimpleModal.tsx create mode 100644 src/components/form/NumberInputField.tsx create mode 100644 src/services/CreateUserService.ts create mode 100644 src/store/manageUserStore.js create mode 100644 src/store/store.js create mode 100644 src/utils/Interfaces.ts diff --git a/package-lock.json b/package-lock.json index c5071690..c5d39414 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,10 @@ "@mui/material": "^5.16.0", "@project-sunbird/client-services": "^7.0.6", "@project-sunbird/telemetry-sdk": "^1.3.0", + "@rjsf/core": "^5.19.3", + "@rjsf/mui": "^5.19.3", + "@rjsf/utils": "^5.19.3", + "@rjsf/validator-ajv8": "^5.19.3", "axios": "^1.7.2", "feather-icons-react": "^0.7.0", "fingerprintjs2": "^2.1.4", @@ -27,7 +31,8 @@ "react-ga4": "^2.1.0", "react-i18next": "^14.1.2", "react-toastify": "^10.0.5", - "sharp": "^0.33.4" + "sharp": "^0.33.4", + "zustand": "^4.5.4" }, "devDependencies": { "@types/fingerprintjs2": "^2.0.0", @@ -1530,6 +1535,97 @@ "resolved": "https://registry.npmjs.org/@project-sunbird/telemetry-sdk/-/telemetry-sdk-1.3.0.tgz", "integrity": "sha512-9vocPJpB08/8pAXDUKQmhCiBxJ9qHxORF1+ot3kJczSnRh/K+POpAWDCR4iJ2+gWXPDE03WIWezshKpyf0RdYQ==" }, + "node_modules/@rjsf/core": { + "version": "5.19.3", + "resolved": "https://registry.npmjs.org/@rjsf/core/-/core-5.19.3.tgz", + "integrity": "sha512-AAzolj+fcFlwk0/5THA7T2JkmYTIUa+fLPM5prFqPw55FwWOa0qC5zIOfkhPS95Z9bfwJv3BubOAiKZ7MOGe8Q==", + "dependencies": { + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "markdown-to-jsx": "^7.4.1", + "nanoid": "^3.3.7", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@rjsf/utils": "^5.19.x", + "react": "^16.14.0 || >=17" + } + }, + "node_modules/@rjsf/mui": { + "version": "5.19.3", + "resolved": "https://registry.npmjs.org/@rjsf/mui/-/mui-5.19.3.tgz", + "integrity": "sha512-8H8+JITEwaS4mw/wLroI9OLijs4bBuEO1qpqhgiugLMjX+8ar3ehVN7luSkamGykliQH5Gp1I978dGIzzV2wmw==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@emotion/react": "^11.7.0", + "@emotion/styled": "^11.6.0", + "@mui/icons-material": "^5.2.0", + "@mui/material": "^5.2.2", + "@rjsf/core": "^5.19.x", + "@rjsf/utils": "^5.19.x", + "react": ">=17" + } + }, + "node_modules/@rjsf/utils": { + "version": "5.19.3", + "resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.19.3.tgz", + "integrity": "sha512-1lG/uMMmnAJE48BHUl4laNY2W2j2gIR2LH4jsxeEMSuFloB06ZuUXLesD03Nz2zQjm66izNmnm5eAmAi3Pa1yQ==", + "dependencies": { + "json-schema-merge-allof": "^0.8.1", + "jsonpointer": "^5.0.1", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.14.0 || >=17" + } + }, + "node_modules/@rjsf/validator-ajv8": { + "version": "5.19.3", + "resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-5.19.3.tgz", + "integrity": "sha512-ah0DY1tGmBDNd0iIjH9/iL3TSflriY8cYPmAwK4aDzGLnwHgD2w8sEfJJjG01pX89rY2CeeYxcwCalwlBlUZ/w==", + "dependencies": { + "ajv": "^8.12.0", + "ajv-formats": "^2.1.1", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@rjsf/utils": "^5.19.x" + } + }, + "node_modules/@rjsf/validator-ajv8/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@rjsf/validator-ajv8/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, "node_modules/@rushstack/eslint-patch": { "version": "1.10.3", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.3.tgz", @@ -1930,6 +2026,42 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2462,6 +2594,27 @@ "node": ">= 0.8" } }, + "node_modules/compute-gcd": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/compute-gcd/-/compute-gcd-1.2.1.tgz", + "integrity": "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==", + "dependencies": { + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, + "node_modules/compute-lcm": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/compute-lcm/-/compute-lcm-1.1.2.tgz", + "integrity": "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==", + "dependencies": { + "compute-gcd": "^1.2.1", + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3599,6 +3752,11 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -4700,6 +4858,27 @@ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" }, + "node_modules/json-schema-compare": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/json-schema-compare/-/json-schema-compare-0.2.2.tgz", + "integrity": "sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ==", + "dependencies": { + "lodash": "^4.17.4" + } + }, + "node_modules/json-schema-merge-allof": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz", + "integrity": "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==", + "dependencies": { + "compute-lcm": "^1.1.2", + "json-schema-compare": "^0.2.2", + "lodash": "^4.17.20" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -4807,6 +4986,14 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -4975,6 +5162,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5003,6 +5200,17 @@ "node": ">=10" } }, + "node_modules/markdown-to-jsx": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.4.7.tgz", + "integrity": "sha512-0+ls1IQZdU6cwM1yu0ZjjiVWYtkbExSyUIFU2ZeDIFuZM1W42Mh4OlJ4nb4apX4H8smxDHRdFaoIVJGwfv5hkg==", + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -5937,6 +6145,14 @@ "node": ">=0.6" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/requireindex": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", @@ -6880,6 +7096,14 @@ "punycode": "^2.1.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", @@ -6894,6 +7118,38 @@ "uuid": "bin/uuid" } }, + "node_modules/validate.io-array": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz", + "integrity": "sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg==" + }, + "node_modules/validate.io-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz", + "integrity": "sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ==" + }, + "node_modules/validate.io-integer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz", + "integrity": "sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==", + "dependencies": { + "validate.io-number": "^1.0.3" + } + }, + "node_modules/validate.io-integer-array": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz", + "integrity": "sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==", + "dependencies": { + "validate.io-array": "^1.0.3", + "validate.io-integer": "^1.0.4" + } + }, + "node_modules/validate.io-number": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz", + "integrity": "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==" + }, "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -7205,6 +7461,33 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.4.tgz", + "integrity": "sha512-/BPMyLKJPtFEvVL0E9E9BTUM63MNyhPGlvxk1XjrfWTUlV+BR8jufjsovHzrtR6YNcBEcL7cMHovL1n9xHawEg==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index a5fef49e..8bc354ad 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,10 @@ "@mui/material": "^5.16.0", "@project-sunbird/client-services": "^7.0.6", "@project-sunbird/telemetry-sdk": "^1.3.0", + "@rjsf/core": "^5.19.3", + "@rjsf/mui": "^5.19.3", + "@rjsf/utils": "^5.19.3", + "@rjsf/validator-ajv8": "^5.19.3", "axios": "^1.7.2", "feather-icons-react": "^0.7.0", "fingerprintjs2": "^2.1.4", @@ -33,7 +37,8 @@ "react-ga4": "^2.1.0", "react-i18next": "^14.1.2", "react-toastify": "^10.0.5", - "sharp": "^0.33.4" + "sharp": "^0.33.4", + "zustand": "^4.5.4" }, "devDependencies": { "@types/fingerprintjs2": "^2.0.0", diff --git a/public/locales/en/common.json b/public/locales/en/common.json index faf86000..bcc1b462 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -23,7 +23,10 @@ "NAME": "Name", "UPDATE_COHORT": "Update Cohort", "EDIT": "Edit", - "DELETE": "Delete" + "DELETE": "Delete", + "SUBMIT": "Submit", + "BACK":"Back" + }, "LOGIN_PAGE": { "USERNAME": "Username", @@ -57,7 +60,9 @@ "SEARCHBAR_PLACEHOLDER": "Search course, topic, student, pdf etc.." }, "LEARNERS": { - "SEARCHBAR_PLACEHOLDER": "Search Learners.." + "SEARCHBAR_PLACEHOLDER": "Search Learners..", + "NEW_LEARNER": "New Learner" + }, "TEAM_LEADERS": { "SEARCHBAR_PLACEHOLDER": "Search Team leaders.." @@ -98,5 +103,60 @@ "CENTER_RENAMED": "Center Renamed Successfully!", "SEND_REQUEST": "Send Request", "REQUEST_TO_DELETE_HAS_BEEN_SENT": "Request to Delete has been sent" + }, + "FORM": { + "FULL_NAME": "Full Name", + "ENTER_FULL_NAME": "Enter FUll Name", + "CONTACT_NUMBER": "Contact Number", + "ENTER_CONTACT_NUMBER": "Enter Contact Number", + "HOW_WAS_LEARNER_MOBILISED": "How Was the Learner Mobilised?", + "SECOND_CHANCE_ALUMNI": "Second Chance Alumni", + "PRATHAM_TEAM_MEMBER": "Pratham Team Member", + "OTHER": "Other", + "AGE": "Age", + "GENDER": "Gender", + "MALE": "Male", + "FEMALE": "Female", + "LEARNERS_PRIMARY_WORK": "Learner's Primary Work", + "ENROLLED_IN_EDUCATIONAL_INSTITUTE": "Enrolled in educational institute", + "OWN_FARMING": "Own farming", + "AGRICULTURAL_FARM_LABORER": "Agricultural farm laborer", + "NON_AGRICULTURAL_LABORER": "Non-agricultural laborer", + "SALARIED_WORK": "Salaried work", + "SELF_EMPLOYMENT": "Self-employment", + "UNEMPLOYED": "Unemployed", + "INVOLVED_IN_DOMESTIC_WORK": "Involved in domestic work", + "FATHER_NAME": "Father’s Name", + "ENTER_YOUR_FATHER_NAME": "Enter Your Father Name", + "CLASS_OR_LAST_PASSED_GRADE": "Class (Last passed grade)", + "NO_SCHOOLING": "No Schooling", + "REASON_FOR_DROPOUT_FROM_SCHOOL": "Reason for Drop Out From School", + "SCHOOL_INACCESSIBLE": "School inaccessible", + "FINANCIAL_CONSTRAINTS": "Financial Constraints", + "LACK_OF_INTEREST": "Lack of Interest", + "FAMILY_RESPONSIBILITIES": "Family responsibilities", + "FAILED": "Failed", + "ILLNESS": "Illness", + "MARRIAGE": "Marriage", + "MIGRATION": "Migration", + "STARTED_VOCATIONAL_COURSE": "Started vocational course", + "STARTED_A_JOB": "Started a job", + "SCHOOL_CLOSURE_DUE_TO_COVID": "School closure due to covid", + "MARITAL_STATUS": "Marital Status", + "UNMARRIED": "Unmarried", + "MARRIED": "Married", + "DIVORCED": "Divorced", + "PHONE_TYPE_AVAILABLE": "Type of Phone Available", + "SMARTPHONE": "Smartphone", + "KEYPAD": "Keypad", + "NO_PHONE": "No Phone", + "IS_IT_YOUR_OWN_PHONE": "Is it your own phone?", + "YES": "Yes", + "NO": "No", + "TYPE_OF_PHONE_AVAILABLE": "Type of Phone Available", + "REASON_FOR_DROP_OUT_FROM_SCHOOL": "Reason for drop out from School", + "EMAIL": "Email", + "YEAR_OF_ JOINING_SCP": "Year of joining SCP", + "ASSIGN_CENTERS": "Assign Centers" } } diff --git a/src/components/AddLeanerModal.tsx b/src/components/AddLeanerModal.tsx new file mode 100644 index 00000000..5f43ac8a --- /dev/null +++ b/src/components/AddLeanerModal.tsx @@ -0,0 +1,184 @@ +import DynamicForm from '@/components/DynamicForm'; +import { + GenerateSchemaAndUiSchema, + customFields, +} from '@/components/GeneratedSchemas'; +import SimpleModal from '@/components/SimpleModal'; +import { getFormRead } from '@/services/CreateUserService'; +import { generateUsernameAndPassword } from '@/utils/Helper'; +import { FormData } from '@/utils/Interfaces'; +import { FormContext, FormContextType } from '@/utils/app.constant'; +import { Button, useTheme } from '@mui/material'; +import { IChangeEvent } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import React, { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Role } from "@/utils/app.constant"; + +interface AddLearnerModalProps { + open: boolean; + onClose: () => void; +} +const AddLearnerModal: React.FC = ({ open, onClose }) => { + const [schema, setSchema] = React.useState(); + const [uiSchema, setUiSchema] = React.useState(); + const [credentials, setCredentials] = React.useState({ username: '', password: '' }); + // const [learnerFormData, setLearnerFormData] = React.useState(); + const { t } = useTranslation(); + const theme = useTheme(); + + const handleGenerateCredentials = () => { + const stateCode = 'MH'; + const newCredentials = generateUsernameAndPassword(stateCode, Role.STUDENT); + setCredentials(newCredentials); + console.log(newCredentials) + }; + + useEffect(() => { + const getAddLearnerFormData = async () => { + try { + const response: FormData = await getFormRead( + FormContext.USERS, + FormContextType.STUDENT + ); + console.log('sortedFields', response); + + if (response) { + const { schema, uiSchema } = GenerateSchemaAndUiSchema(response, t); + setSchema(schema); + setUiSchema(uiSchema); + } + } catch (error) { + console.error('Error fetching form data:', error); + } + }; + getAddLearnerFormData(); + }, []); + + const handleSubmit = ( + data: IChangeEvent, + event: React.FormEvent + ) => { + // setOpenModal(true); + const target = event.target as HTMLFormElement; + const elementsArray = Array.from(target.elements); + + for (const element of elementsArray) { + if ( + (element instanceof HTMLInputElement || + element instanceof HTMLSelectElement || + element instanceof HTMLTextAreaElement) && + (element.value === '' || + (Array.isArray(element.value) && element.value.length === 0)) + ) { + element.focus(); + return; + } + } + console.log('Form data submitted:', data.formData); + }; + + const handleChange = (event: IChangeEvent) => { + console.log('Form data changed:', event.formData); + // setFormData({ + // ...formData, + // [event.target.name]: event.target.value + // }); + }; + + const handleError = (errors: any) => { + console.log('Form errors:', errors); + }; + + const CustomSubmitButton: React.FC<{ onClose: () => void }> = ({ onClose }) => ( +
+ <> + + + +
+ ); + + const primaryActionHandler = () => { + onClose(); + }; + + const secondaryActionHandler = async (e: React.FormEvent) => { + // console.log('Secondary action handler clicked'); + e.preventDefault(); + handleGenerateCredentials(); + // onClose(); + // try { + // const response = await createUser(learnerFormData); + // console.log('User created successfully', response); + // } catch (error) { + // console.error('Error creating user', error); + // } + }; + + return ( + <> + + {schema && uiSchema && ( + + + + )} + + + ); +}; + +export default AddLearnerModal; diff --git a/src/components/CustomRadioWidget.tsx b/src/components/CustomRadioWidget.tsx new file mode 100644 index 00000000..b8d59c08 --- /dev/null +++ b/src/components/CustomRadioWidget.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import Radio from '@mui/material/Radio'; +import RadioGroup from '@mui/material/RadioGroup'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import FormLabel from '@mui/material/FormLabel'; +import { WidgetProps } from '@rjsf/utils'; + +interface CustomRadioWidgetProps { + value: string; + id: string; + required: boolean; + disabled: boolean; + readonly: boolean; + label: string; + options: any; + onChange: any; +} +const CustomRadioWidget: React.FC = ({ + id, + value, + required, + disabled, + readonly, + label, + options, + onChange, +}) => { + const handleChange = (event: any) => { + onChange(event.target.value); + }; + + return ( +
+ {label} + + {options?.enumOptions?.map((option: any) => ( + } + label={option.label} + disabled={disabled || readonly} + /> + ))} + +
+ ); +}; + +export default CustomRadioWidget; diff --git a/src/components/DynamicForm.tsx b/src/components/DynamicForm.tsx new file mode 100644 index 00000000..07cc7303 --- /dev/null +++ b/src/components/DynamicForm.tsx @@ -0,0 +1,151 @@ +import { IChangeEvent, withTheme } from '@rjsf/core'; +import { Theme as MaterialUITheme } from '@rjsf/mui'; +import { RJSFSchema, RegistryFieldsType, WidgetProps } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; +import { useTranslation } from 'next-i18next'; +import React, { ReactNode } from 'react'; +import CustomRadioWidget from './CustomRadioWidget'; +import MultiSelectCheckboxes from './MultiSelectCheckboxes'; + +const FormWithMaterialUI = withTheme(MaterialUITheme); + +interface DynamicFormProps { + schema: any; + uiSchema: object; + formData?: object; + onSubmit: ( + data: IChangeEvent, + event: React.FormEvent + ) => void | Promise; + onChange: (event: IChangeEvent) => void; + onError: (errors: any) => void; + showErrorList: boolean; + widgets: { + [key: string]: React.FC>; + }; + customFields: { + [key: string]: React.FC>; + }; + children?: ReactNode; +} +const DynamicForm: React.FC = ({ + schema, + uiSchema, + formData, + onSubmit, + onChange, + onError, + customFields, + children, +}) => { + const widgets = { + MultiSelectCheckboxes: MultiSelectCheckboxes, + CustomRadioWidget: CustomRadioWidget, + }; + const { t } = useTranslation(); + + // console.log('CustomErrorList', CustomErrorList); + + const handleError = (errors: any) => { + if (errors.length > 0) { + // Adjust the selector based on the actual structure of the form element names + const property = errors[0].property?.replace(/^root\./, ''); + const errorField = document.querySelector( + `[name$="${property}"]` + ) as HTMLElement; + + if (errorField) { + errorField.focus(); + } else { + // If the name-based selector fails, try to select by ID as a fallback + const fallbackField = document.getElementById(property) as HTMLElement; + if (fallbackField) { + fallbackField.focus(); + } + } + } + onError(errors); + }; + + function transformErrors(errors: any) { + console.log('errors', errors); + console.log('schema', schema); + return errors.map((error: any) => { + switch (error.name) { + case 'required': { + // error.message = t('FORM_ERROR_MESSAGES.FIELD_REQUIRED', { + // field: t(`FORM.${schema.properties[error.property].title}`), + // }); + + error.message = t('FORM_ERROR_MESSAGES.THIS_IS_REQUIRED_FIELD'); + break; + } + case 'pattern': { + const property = error.property.substring(1); + console.log('schema===>', schema); + if (schema.properties?.[property]?.validation?.includes('numeric')) { + error.message = t('FORM_ERROR_MESSAGES.ENTER_ONLY_DIGITS'); + } else if ( + schema.properties?.[property]?.validation?.includes( + 'characters-with-space' + ) + ) { + error.message = t( + 'FORM_ERROR_MESSAGES.NUMBER_AND_SPECIAL_CHARACTERS_NOT_ALLOWED' + ); + } + break; + } + case 'minLength': { + const property = error.property.substring(1); + if (schema.properties?.[property]?.validation?.includes('numeric')) { + error.message = t('FORM_ERROR_MESSAGES.MIN_LENGTH_DIGITS_ERROR', { + minLength: schema.properties?.[property]?.minLength, + }); + } + break; + } + case 'maxLength': { + const property = error.property.substring(1); + if (schema.properties?.[property]?.validation?.includes('numeric')) { + error.message = t('FORM_ERROR_MESSAGES.MAX_LENGTH_DIGITS_ERROR', { + maxLength: schema.properties?.[property]?.maxLength, + }); + } + break; + } + } + + return error; + }); + } + + function handleChange(event: any) { + console.log('Form data event:', event); + onChange(event); + } + + return ( +
+ + {children} + +
+ ); +}; + +export default DynamicForm; \ No newline at end of file diff --git a/src/components/GeneratedSchemas.ts b/src/components/GeneratedSchemas.ts new file mode 100644 index 00000000..25798a89 --- /dev/null +++ b/src/components/GeneratedSchemas.ts @@ -0,0 +1,214 @@ +import { UiSchema } from '@rjsf/utils'; +import { JSONSchema7 } from 'json-schema'; +import NumberInputField from './form/NumberInputField'; +import { FormData, Field, FieldOption } from '@/utils/Interfaces'; + +export const customFields = { + NumberInputField: NumberInputField, +}; + +export const GenerateSchemaAndUiSchema = ( + formData: FormData, + t: (key: string) => string +) => { + const schema: JSONSchema7 = { + //Form schema + title: '', + description: '', + type: 'object', + required: [], + properties: {}, + dependencies: {}, + }; + + const uiSchema: UiSchema = {}; //form ui schema + + // console.log('FormData', formData) + formData?.fields?.forEach((field: Field) => { + const { + label, + name, + type, + isEditable, + validation, + options, + isMultiSelect, + maxSelections, + dependsOn, + pattern, + required, + } = field; + + const fieldSchema: any = { + title: t(`FORM.${label}`), + fieldId: field.fieldId ?? field.fieldId, + }; + + const fieldUiSchema: any = {}; + + switch (type) { + case 'text': + fieldSchema.type = 'string'; + break; + case 'email': + fieldSchema.type = 'string'; + break; + case 'numeric': + fieldSchema.type = 'number'; + + if (field?.maxLength) { + fieldSchema.maximum = Number(field.maxLength); + } + + if (field?.minLength !== undefined && field?.minLength !== null) { + fieldSchema.minimum = Number(field.minLength); + } + + // fieldUiSchema['ui:field'] = 'NumberInputField'; + break; + case 'drop_down': + fieldSchema.type = 'string'; + fieldSchema.isDropdown = true; + // fieldSchema.oneOf = options.map((opt: FieldOption) => ({ + // const: opt.value, + // title: + // t(`FORM.${opt.label}`) === `FORM.${opt.label}` + // ? opt.label + // : t(`FORM.${opt.label}`), + // })); + fieldUiSchema['ui:widget'] = 'select'; + break; + case 'checkbox': + fieldSchema.type = 'array'; + fieldSchema.checkbox = true; + fieldSchema.items = { + type: 'string', + oneOf: options.map((opt: FieldOption) => ({ + const: opt.value, + title: + t(`FORM.${opt.label}`) === `FORM.${opt.label}` + ? opt.label + : t(`FORM.${opt.label}`), + })), + }; + fieldSchema.uniqueItems = true; + fieldUiSchema['ui:widget'] = 'checkboxes'; + break; + case 'radio': + fieldSchema.type = 'string'; + fieldSchema.oneOf = options.map((opt: FieldOption) => ({ + const: opt.value, + title: + t(`FORM.${opt.label}`) === `FORM.${opt.label}` + ? opt.label + : t(`FORM.${opt.label}`), + })); + fieldUiSchema['ui:widget'] = 'CustomRadioWidget'; + break; + default: + break; + } + + if (isEditable === false) { + fieldUiSchema['ui:disabled'] = true; + } + + if (dependsOn) { + // Handle dependencies logic if needed + } + + // if (isMultiSelect && type === 'drop_down') { + // fieldSchema.type = 'array'; + // fieldSchema.items = { + // type: 'string', + // oneOf: options.map((opt: FieldOption) => ({ + // const: opt.value, + // title: + // t(`FORM.${opt.label}`) === `FORM.${opt.label}` + // ? opt.label + // : t(`FORM.${opt.label}`), + // })), + // }; + // fieldSchema.uniqueItems = true; + // fieldUiSchema['ui:widget'] = 'select'; + // } + + if (isMultiSelect && type === 'drop_down') { + fieldSchema.type = 'array'; + fieldSchema.items = { + type: 'string', + enum: options.map((opt: FieldOption) => opt.value), + }; + fieldSchema.uniqueItems = true; + fieldSchema.enumNames = options.map((opt: FieldOption) => + t(`FORM.${opt.label}`) === `FORM.${opt.label}` + ? opt.label + : t(`FORM.${opt.label}`) + ); + if (maxSelections) { + fieldSchema.maxItems = maxSelections; + } + fieldUiSchema['ui:widget'] = 'select'; + } + + if (!isMultiSelect && type === 'drop_down') { + fieldSchema.type = 'string'; + fieldSchema.isDropdown = true; + fieldSchema.oneOf = options.map((opt: FieldOption) => ({ + const: opt.value, + title: + t(`FORM.${opt.label}`) === `FORM.${opt.label}` + ? opt.label + : t(`FORM.${opt.label}`), + })); + fieldUiSchema['ui:widget'] = 'select'; + } + + if (isMultiSelect && type === 'checkbox') { + fieldSchema.type = 'array'; + fieldSchema.items = { + type: 'string', + oneOf: options.map((opt: FieldOption) => ({ + const: opt.value, + title: + t(`FORM.${opt.label}`) === `FORM.${opt.label}` + ? opt.label + : t(`FORM.${opt.label}`), + })), + }; + fieldSchema.uniqueItems = true; + fieldUiSchema['ui:widget'] = 'MultiSelectCheckboxes'; + } + + if (pattern) { + fieldSchema.pattern = pattern; + // fieldUiSchema["ui:help"]= "Only alphabetic characters are allowed."; + } + + if (required) { + schema.required?.push(name); + } + + if (field?.minLength) { + fieldSchema.minLength = Number(field.minLength); + } + + if (field?.maxLength) { + fieldSchema.maxLength = Number(field.maxLength); + } + + if (field?.validation) { + if (field?.validation?.includes('numeric')) { + // fieldUiSchema['ui:field'] = 'NumberInputField'; + } + fieldSchema.validation = field.validation; + } + + if (schema !== undefined && schema.properties) { + schema.properties[name] = fieldSchema; + uiSchema[name] = fieldUiSchema; + } + }); + + return { schema, uiSchema, customFields }; +}; \ No newline at end of file diff --git a/src/components/HeaderComponent.tsx b/src/components/HeaderComponent.tsx index 51170505..3384f64e 100644 --- a/src/components/HeaderComponent.tsx +++ b/src/components/HeaderComponent.tsx @@ -68,7 +68,8 @@ const HeaderComponent = ({ handleSortChange, handleFilterChange, showStateDropdown = true, - handleSearch + handleSearch, + handleAddUserClick }: any) => { const { t } = useTranslation(); const theme = useTheme(); @@ -275,6 +276,8 @@ const HeaderComponent = ({ mt: isMobile ? "10px" : "16px", boxShadow: "0px 0px 10px rgba(0, 0, 0, 0.1)", }} + onClick={handleAddUserClick} + > + )} + + {secondaryText && ( + + )} + + ) : null} + + + ); +}; + +export default SimpleModal; diff --git a/src/components/UserTable.tsx b/src/components/UserTable.tsx index 765029fb..b1c63ed1 100644 --- a/src/components/UserTable.tsx +++ b/src/components/UserTable.tsx @@ -50,7 +50,8 @@ interface Cohort { interface UserTableProps { role: string; userType: string, - searchPlaceholder: string + searchPlaceholder: string, + handleAddUserClick: any } const columns = [ // { @@ -124,7 +125,7 @@ const columns = [ }, ]; -const UserTable: React.FC = ({ role , userType, searchPlaceholder}) => { +const UserTable: React.FC = ({ role , userType, searchPlaceholder, handleAddUserClick}) => { const [selectedState, setSelectedState] = React.useState([]); const [selectedStateCode, setSelectedStateCode] = useState(""); const [selectedDistrict, setSelectedDistrict] = React.useState([]); @@ -471,6 +472,7 @@ const UserTable: React.FC = ({ role , userType, searchPlaceholde setOtherReason(""); setIsDeleteModalOpen(false); }; + const handleDeleteUser = async (category: string) => { try { console.log(selectedUserId); @@ -508,8 +510,9 @@ const UserTable: React.FC = ({ role , userType, searchPlaceholde handleSortChange: handleSortChange, selectedFilter: selectedFilter, handleFilterChange: handleFilterChange, - handleSearch:handleSearch - }; + handleSearch:handleSearch, + handleAddUserClick: handleAddUserClick + }; return ( diff --git a/src/components/form/NumberInputField.tsx b/src/components/form/NumberInputField.tsx new file mode 100644 index 00000000..59467dc0 --- /dev/null +++ b/src/components/form/NumberInputField.tsx @@ -0,0 +1,52 @@ +import { TextField, useTheme } from '@mui/material'; +import React, { useState } from 'react'; + + +const NumberInputField = (props: any) => { + const theme = useTheme(); + const { onChange, ...rest } = props; + + const [error, setError] = useState(""); + + console.log('NumberInputField', props); + const handleChange = (event: any) => { + const value = event.target.value; + + const regex = props?.schema?.maxLength ? new RegExp(`^\\d{0,${props.schema.maxLength}}$`) : /^\d*$/; + + if (regex.test(value)) { // Allow only up to 10 digits + if (props?.schema?.maxLength ) { + if (value.length === props.schema.maxLength) { + setError(""); // Clear any existing error + onChange(Number(value)); + } else { + setError(`Must be exactly ${props.schema.maxLength} digits`); + onChange(undefined); // Clear the form data + } + } + } + }; + + return ( + // + <> + +

{error}

+ + ); +}; + +export default NumberInputField; diff --git a/src/pages/faciliator.tsx b/src/pages/faciliator.tsx index 8e453cf2..21241571 100644 --- a/src/pages/faciliator.tsx +++ b/src/pages/faciliator.tsx @@ -6,10 +6,11 @@ import { Role } from "@/utils/app.constant"; const Faciliator: React.FC = () => { const { t } = useTranslation(); - + const handleAddFaciliatorClick = () => { + }; return ( <> - + ); }; diff --git a/src/pages/learners.tsx b/src/pages/learners.tsx index 35ffd331..3d82dd20 100644 --- a/src/pages/learners.tsx +++ b/src/pages/learners.tsx @@ -3,13 +3,28 @@ import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import UserTable from "@/components/UserTable"; import { useTranslation } from "next-i18next"; import { Role } from "@/utils/app.constant"; +import AddLearnerModal from '@/components/AddLeanerModal'; const Learners: React.FC = () => { const { t } = useTranslation(); + const [openAddLearnerModal, setOpenAddLearnerModal] = React.useState(false); + const handleOpenAddLearnerModal = () => { + setOpenAddLearnerModal(true); +}; +const handleCloseAddLearnerModal = () => { + setOpenAddLearnerModal(false); +}; + const handleAddLearnerClick = () => { + handleOpenAddLearnerModal(); + }; return ( <> - + + ); }; diff --git a/src/pages/teamLeader.tsx b/src/pages/teamLeader.tsx index 48b4eb5f..c3e73edf 100644 --- a/src/pages/teamLeader.tsx +++ b/src/pages/teamLeader.tsx @@ -7,10 +7,11 @@ import { Role } from "@/utils/app.constant"; const TeamLeader: React.FC = () => { const { t } = useTranslation(); - + const handleAddTeamLeaderClick = () => { + }; return ( <> - + ); }; diff --git a/src/services/CreateUserService.ts b/src/services/CreateUserService.ts new file mode 100644 index 00000000..367144a9 --- /dev/null +++ b/src/services/CreateUserService.ts @@ -0,0 +1,37 @@ +import { get, post } from './RestClient'; +import { createUserParam } from '../utils/Interfaces'; + +export const getFormRead = async ( + context: string, + contextType: string +): Promise => { + const apiUrl: string = `${process.env.NEXT_PUBLIC_BASE_URL}/form/read?context=${context}&contextType=${contextType}`; + try { + let response = await get(apiUrl); + + const sortedFields = response?.data?.result.fields?.sort( + (a: { order: string }, b: { order: string }) => + parseInt(a.order) - parseInt(b.order) + ); + const formData = { + formid: response?.data?.result?.formid, + title: response?.data?.result?.title, + fields: sortedFields, + }; + return formData; + } catch (error) { + console.error('error in getting cohort details', error); + // throw error; + } +}; + +export const createUser = async (userData: any): Promise => { + const apiUrl: string = `${process.env.NEXT_PUBLIC_BASE_URL}/create`; + try { + const response = await post(apiUrl, userData); + return response?.data?.result; + } catch (error) { + console.error('error in getting cohort list', error); + // throw error; + } +}; \ No newline at end of file diff --git a/src/store/manageUserStore.js b/src/store/manageUserStore.js new file mode 100644 index 00000000..2d913a63 --- /dev/null +++ b/src/store/manageUserStore.js @@ -0,0 +1,35 @@ +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; + +const manageUserStore = create( + persist( + (set) => ({ + deleteId: '', + learnerDeleteId: '', + blockCode: '', + districtCode: '', + stateCode: '', + blockId: 'a717bb68-5c8a-45cb-b6dd-376caa605736', + districtId: 'aecb84c9-fe4c-4960-817f-3d228c0c7300', + stateId: '61b5909a-0b45-4282-8721-e614fd36d7bd', + setCohortDeleteId: (newCohortDeleteId) => + set((state) => ({ deleteId: newCohortDeleteId })), + setCohortLearnerDeleteId: (newCohortLearnerDeleteId) => + set((state) => ({ learnerDeleteId: newCohortLearnerDeleteId })), + setBlockCode: (newBlockCode) => set(() => ({ blockCode: newBlockCode })), + setDistrictCode: (newDistrictCode) => + set(() => ({ districtCode: newDistrictCode })), + setStateCode: (newStateCode) => set(() => ({ stateCode: newStateCode })), + setBlockId: (newBlockId) => set(() => ({ blockId: newBlockId })), + setDistrictId: (newDistrictId) => + set(() => ({ districtId: newDistrictId })), + setStateId: (newStateId) => set(() => ({ stateId: newStateId })), + }), + { + name: 'teacherApp', + getStorage: () => localStorage, + } + ) +); + +export default manageUserStore; \ No newline at end of file diff --git a/src/store/store.js b/src/store/store.js new file mode 100644 index 00000000..d773d830 --- /dev/null +++ b/src/store/store.js @@ -0,0 +1,22 @@ +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; + +const useStore = create( + persist( + (set) => ({ + value: '', + cohorts: [], + userRole: '', + pairs: [], + setValue: (newValue) => set((state) => ({ value: newValue })), + setUserRole: (newRole) => set((state) => ({ userRole: newRole })), + setCohorts: (newCohorts) => set(() => ({ cohorts: newCohorts })), + }), + { + name: 'teacherApp', + getStorage: () => localStorage, + } + ) +); + +export default useStore; diff --git a/src/utils/Helper.ts b/src/utils/Helper.ts index 0a9c3915..eee72589 100644 --- a/src/utils/Helper.ts +++ b/src/utils/Helper.ts @@ -29,4 +29,18 @@ export const generateUUID = () => { }); }; - \ No newline at end of file + export const generateUsernameAndPassword = ( + stateCode: string, + role: string + ) => { + const currentYear = new Date().getFullYear().toString().slice(-2); + const randomNum = Math.floor(10000 + Math.random() * 90000).toString(); + + const username = + role === 'F' + ? `FSC${stateCode}${currentYear}${randomNum}` + : `SC${stateCode}${currentYear}${randomNum}`; + const password = randomNum; + + return { username, password }; + }; \ No newline at end of file diff --git a/src/utils/Interfaces.ts b/src/utils/Interfaces.ts new file mode 100644 index 00000000..e4367e92 --- /dev/null +++ b/src/utils/Interfaces.ts @@ -0,0 +1,53 @@ + + +export interface FieldOption { + label: string; + value: string; +} + +export interface Field { + name: string; + type: 'text' | 'numeric' | 'drop_down' | 'checkbox' | 'radio' | 'email'; + label: string; + order: string; + coreField: number; + dependsOn: string | boolean | null; + isEditable: boolean; + isPIIField: boolean | null; + validation?: string[]; + placeholder: string; + isMultiSelect: boolean; + maxSelections: number | null; + sourceDetails: Record; + options: FieldOption[]; + hint?: string | null; + pattern?: string | null; + maxLength?: number | null; + minLength?: number | null; + fieldId: string; + required?: boolean; +} +export interface TenantCohortRoleMapping { + tenantId: string; + roleId: string; +} + +export interface CustomField { + fieldId: string; + value: string; +} +export interface FormData { + formid: string; + title: string; + fields: Field[]; +} +export interface createUserParam { + username: string; + name: string; + email: string; + password: string; + tenantCohortRoleMapping: TenantCohortRoleMapping[]; + customFields: CustomField[]; +} + + diff --git a/src/utils/app.constant.ts b/src/utils/app.constant.ts index 26e1f91e..d00cdb71 100644 --- a/src/utils/app.constant.ts +++ b/src/utils/app.constant.ts @@ -18,3 +18,21 @@ export enum Storage { NAME = "name", USER_ID = "userId", } +export enum FormContext { + USERS = 'USERS' +} + +export enum FormContextType { + STUDENT = 'STUDENT', + TEACHER = 'TEACHER', + TEAM_LEADER = 'TEAMLEADER', +} + +export enum RoleId { + STUDENT = "493c04e2-a9db-47f2-b304-503da358d5f4", + TEACHER = "3bde0028-6900-4900-9d05-eeb608843718", + TEAM_LEADER="9dd9328f-1bc7-444f-96e3-c5e1daa3514a", + ADMIN = "ee482faf-8a41-45fe-9656-5533dd6a787c", +} + +