diff --git a/README.md b/README.md index 2fdbbf6..08c501f 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ All this task must be done in 1 day - in src/utils/MkdSDK.jsx implement Line 91 - in src/pages/AdminLoginPage.jsx implement Line 30 - once login successful, call snackbar component to show logged in toast. DONT use 3rd party library -- in src/authContext.jsx implement 16 -- in src/authContext.jsx implement 40 to check if token still valid +- in src/context/Auth/AuthContext.jsx implement 16 +- in src/context/Auth/AuthContext.jsx implement 40 to check if token still valid - There's a bug that it flickers Page Not Found - once logged in go to dashboard page like figma file https://www.figma.com/file/veiESwD61KJBa7BpEHtbdl/react-task-2?node-id=1086%3A15525 @@ -23,6 +23,56 @@ All this task must be done in 1 day - Please READ SDK file and reuse code when you can. DO NOT REINVENT THE WHEEL. - Use React Drag and drop library https://react-dnd.github.io/react-dnd/about to be able to rearrange the rows and columns in the table in dashboard. On Refresh, the columns go back to default +### Table Task + +- in src/pages/AdminListReceipts.jsx - we have a table listing receipts + +1. fix the bind issue in src/components/MkdListTable/MkdListTableBindOperations.jsx - all //TO DO + For example + + + the edit action binds via the bind property to a column "receipt_status" + if the value of receipt_status is 1 then the edit should be hidden, i.e not shown + +2. in src/components/MkdListTable/MkdListTableRow.jsx each column has a format it should be rendered in + + - "line_items" and "receipt_charges" have the list property `true`, listType: `json|object_array` could be `json|number_array` or `json|string_array` but in this case it is the `json|object_array` + + - using the action which tells you what key in the array of objects you need to work on + operation is either to `list` all the values and return an array or `add` to add all the values of the key and return the result + +- src/utils/utils.jsx - Line 179 + + ## Login ``` diff --git a/index.html b/index.html index ac2ac2d..e0271da 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,8 @@ - + + Vite App diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..91d8261 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,17 @@ + + { + "compilerOptions": { + "jsx": "react", + "baseUrl": ".", + "paths": { + "Components/*": ["src/components/*"], + "Pages/*": ["src/pages/*"], + "Utils/*": ["src/utils/*"], + "Assets/*": ["src/assets/*"], + "Context/*": ["src/context/*"], + "Routes/*": ["src/routes/*"], + "Hooks/*": ["src/hooks/*"], + "Src/*": ["src/*"] + } + } + } diff --git a/package-lock.json b/package-lock.json index 4864f7b..f774915 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,9 +12,13 @@ "react": "^18.0.0", "react-dom": "^18.0.0", "react-hook-form": "^7.31.2", + "react-icons": "^5.2.1", "react-loading-skeleton": "^3.1.0", "react-router": "^6.2.2", "react-router-dom": "^6.2.2", + "react-spinners": "^0.13.8", + "react-toggle": "^4.1.3", + "react-tooltip": "^5.27.0", "yup": "^0.32.11" }, "devDependencies": { @@ -417,6 +421,28 @@ "node": ">=6.9.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.3.tgz", + "integrity": "sha512-1ZpCvYf788/ZXOhRQGFxnYQOVgeU+pi0i+d0Ow34La7qjIXETi6RNswGVKkA6KcDO8/+Ysu2E/CeUmmeEBDvTg==", + "dependencies": { + "@floating-ui/utils": "^0.2.3" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.6.tgz", + "integrity": "sha512-qiTYajAnh3P+38kECeffMSQgbvXty2VB6rS+42iWR4FPIlZjLK84E9qtLnMTLIpPz2znD/TaFqaiavMUrS+Hcw==", + "dependencies": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.3" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.3.tgz", + "integrity": "sha512-XGndio0l5/Gvd6CLIABvsav9HHezgDFFhDfHk1bvLfr9ni8dojqLSvBbotJEjmIwNHL7vK4QzBJTdBRoB+c1ww==" + }, "node_modules/@hookform/resolvers": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.9.1.tgz", @@ -776,6 +802,11 @@ "node": ">= 6" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, "node_modules/color-convert": { "version": "1.9.3", "dev": true, @@ -1236,6 +1267,15 @@ "node": ">=0.10.0" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-hash": { "version": "3.0.0", "dev": true, @@ -1396,6 +1436,17 @@ "dev": true, "license": "MIT" }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "peer": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/property-expr": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz", @@ -1467,6 +1518,20 @@ "react": "^16.8.0 || ^17 || ^18" } }, + "node_modules/react-icons": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz", + "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "peer": true + }, "node_modules/react-loading-skeleton": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/react-loading-skeleton/-/react-loading-skeleton-3.1.0.tgz", @@ -1507,6 +1572,41 @@ "react-dom": ">=16.8" } }, + "node_modules/react-spinners": { + "version": "0.13.8", + "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.13.8.tgz", + "integrity": "sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==", + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-toggle": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/react-toggle/-/react-toggle-4.1.3.tgz", + "integrity": "sha512-WoPrvbwfQSvoagbrDnXPrlsxwzuhQIrs+V0I162j/s+4XPgY/YDAUmHSeWiroznfI73wj+MBydvW95zX8ABbSg==", + "dependencies": { + "classnames": "^2.2.5" + }, + "peerDependencies": { + "prop-types": ">= 15.3.0 < 19", + "react": ">= 15.3.0 < 19", + "react-dom": ">= 15.3.0 < 19" + } + }, + "node_modules/react-tooltip": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.27.0.tgz", + "integrity": "sha512-JXROcdfCEbCqkAkh8LyTSP3guQ0dG53iY2E2o4fw3D8clKzziMpE6QG6CclDaHELEKTzpMSeAOsdtg0ahoQosw==", + "dependencies": { + "@floating-ui/dom": "^1.6.1", + "classnames": "^2.3.0" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -2037,6 +2137,28 @@ "to-fast-properties": "^2.0.0" } }, + "@floating-ui/core": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.3.tgz", + "integrity": "sha512-1ZpCvYf788/ZXOhRQGFxnYQOVgeU+pi0i+d0Ow34La7qjIXETi6RNswGVKkA6KcDO8/+Ysu2E/CeUmmeEBDvTg==", + "requires": { + "@floating-ui/utils": "^0.2.3" + } + }, + "@floating-ui/dom": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.6.tgz", + "integrity": "sha512-qiTYajAnh3P+38kECeffMSQgbvXty2VB6rS+42iWR4FPIlZjLK84E9qtLnMTLIpPz2znD/TaFqaiavMUrS+Hcw==", + "requires": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.3" + } + }, + "@floating-ui/utils": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.3.tgz", + "integrity": "sha512-XGndio0l5/Gvd6CLIABvsav9HHezgDFFhDfHk1bvLfr9ni8dojqLSvBbotJEjmIwNHL7vK4QzBJTdBRoB+c1ww==" + }, "@hookform/resolvers": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.9.1.tgz", @@ -2262,6 +2384,11 @@ } } }, + "classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, "color-convert": { "version": "1.9.3", "dev": true, @@ -2551,6 +2678,12 @@ "version": "0.1.2", "dev": true }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "peer": true + }, "object-hash": { "version": "3.0.0", "dev": true @@ -2629,6 +2762,17 @@ "version": "4.2.0", "dev": true }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "peer": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "property-expr": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz", @@ -2661,6 +2805,18 @@ "integrity": "sha512-A0bsgZZUnGdG68sXLBNMN7zRYKbYc/ESjDkjrJZ8PZ8/96EQ0IwMfYY3wpopt+yn2+Mm3APEUkw+JdjYQSRVJA==", "requires": {} }, + "react-icons": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz", + "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==", + "requires": {} + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "peer": true + }, "react-loading-skeleton": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/react-loading-skeleton/-/react-loading-skeleton-3.1.0.tgz", @@ -2688,6 +2844,29 @@ "react-router": "6.3.0" } }, + "react-spinners": { + "version": "0.13.8", + "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.13.8.tgz", + "integrity": "sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==", + "requires": {} + }, + "react-toggle": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/react-toggle/-/react-toggle-4.1.3.tgz", + "integrity": "sha512-WoPrvbwfQSvoagbrDnXPrlsxwzuhQIrs+V0I162j/s+4XPgY/YDAUmHSeWiroznfI73wj+MBydvW95zX8ABbSg==", + "requires": { + "classnames": "^2.2.5" + } + }, + "react-tooltip": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.27.0.tgz", + "integrity": "sha512-JXROcdfCEbCqkAkh8LyTSP3guQ0dG53iY2E2o4fw3D8clKzziMpE6QG6CclDaHELEKTzpMSeAOsdtg0ahoQosw==", + "requires": { + "@floating-ui/dom": "^1.6.1", + "classnames": "^2.3.0" + } + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", diff --git a/package.json b/package.json index 075c7ac..817a50f 100644 --- a/package.json +++ b/package.json @@ -8,13 +8,17 @@ "preview": "vite preview" }, "dependencies": { + "@hookform/resolvers": "^2.8.10", "react": "^18.0.0", "react-dom": "^18.0.0", - "@hookform/resolvers": "^2.8.10", "react-hook-form": "^7.31.2", + "react-icons": "^5.2.1", "react-loading-skeleton": "^3.1.0", "react-router": "^6.2.2", "react-router-dom": "^6.2.2", + "react-spinners": "^0.13.8", + "react-toggle": "^4.1.3", + "react-tooltip": "^5.27.0", "yup": "^0.32.11" }, "devDependencies": { diff --git a/src/App.jsx b/src/App.jsx index 0df1193..2c3e714 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,6 +1,6 @@ -import AuthProvider from "./authContext"; -import GlobalProvider from "./globalContext"; import { BrowserRouter as Router } from "react-router-dom"; +import { AuthProvider } from "Context/Auth"; +import { GlobalProvider } from "Context/Global"; import Main from "./main"; function App() { diff --git a/src/assets/images/index.js b/src/assets/images/index.js new file mode 100644 index 0000000..7ed7fca --- /dev/null +++ b/src/assets/images/index.js @@ -0,0 +1,2 @@ +export { default as LoginBgNew } from "./login-new-bg.png"; +export { default as NoDataFoundImg } from "./no_data_found.png"; diff --git a/src/assets/images/login-new-bg.png b/src/assets/images/login-new-bg.png new file mode 100644 index 0000000..5c7cf5b Binary files /dev/null and b/src/assets/images/login-new-bg.png differ diff --git a/src/assets/images/mkd_logo.png b/src/assets/images/mkd_logo.png new file mode 100644 index 0000000..8945fb2 --- /dev/null +++ b/src/assets/images/mkd_logo.png @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/no_data_found.png b/src/assets/images/no_data_found.png new file mode 100644 index 0000000..564b2a1 Binary files /dev/null and b/src/assets/images/no_data_found.png differ diff --git a/src/assets/svgs/AddressbookIcon.jsx b/src/assets/svgs/AddressbookIcon.jsx new file mode 100644 index 0000000..d8a4fd6 --- /dev/null +++ b/src/assets/svgs/AddressbookIcon.jsx @@ -0,0 +1,29 @@ +import React from "react"; + +const AddressbookIcon = ({ + className = "", + stroke = "black", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default AddressbookIcon; diff --git a/src/assets/svgs/AvatarIcon.jsx b/src/assets/svgs/AvatarIcon.jsx new file mode 100644 index 0000000..9986178 --- /dev/null +++ b/src/assets/svgs/AvatarIcon.jsx @@ -0,0 +1,37 @@ +import React from "react"; + +const AvatarIcon = ({ className = "", fill = "#A8A8A8" }) => { + return ( + + + + + + + ); +}; + +export default AvatarIcon; diff --git a/src/assets/svgs/AwaitIcon.jsx b/src/assets/svgs/AwaitIcon.jsx new file mode 100644 index 0000000..16db4b2 --- /dev/null +++ b/src/assets/svgs/AwaitIcon.jsx @@ -0,0 +1,33 @@ +import React from "react"; + +const AwaitIcon = ({ + className = "", + stroke = "#2D9F75", + fill = "#7B1113", + onClick = () => {}, +}) => { + return ( + + + + + ); +}; + +export default AwaitIcon; diff --git a/src/assets/svgs/BigPinIcon.jsx b/src/assets/svgs/BigPinIcon.jsx new file mode 100644 index 0000000..a57cd1d --- /dev/null +++ b/src/assets/svgs/BigPinIcon.jsx @@ -0,0 +1,74 @@ +import React from "react"; + +const BigPinIcon = ({ + className = "", + stroke = "#F2AE40", + onClick = () => {}, +}) => { + return ( + + + + + + + + + + + + + + + + + + + ); +}; + +export default BigPinIcon; diff --git a/src/assets/svgs/CaretLeft.jsx b/src/assets/svgs/CaretLeft.jsx new file mode 100644 index 0000000..371d048 --- /dev/null +++ b/src/assets/svgs/CaretLeft.jsx @@ -0,0 +1,26 @@ +import React from "react"; + +export const CaretLeft = ({ + className = "", + stroke = "black", + fill = "none", +}) => { + return ( + + + + ); +}; diff --git a/src/assets/svgs/CheckIcon.jsx b/src/assets/svgs/CheckIcon.jsx new file mode 100644 index 0000000..c035796 --- /dev/null +++ b/src/assets/svgs/CheckIcon.jsx @@ -0,0 +1,29 @@ +import React from "react"; + +const CheckIcon = ({ + className = "", + stroke = "#2D9F75", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default CheckIcon; diff --git a/src/assets/svgs/ChecklistIcon.jsx b/src/assets/svgs/ChecklistIcon.jsx new file mode 100644 index 0000000..c9d4d62 --- /dev/null +++ b/src/assets/svgs/ChecklistIcon.jsx @@ -0,0 +1,29 @@ +import React from "react"; + +const ChecklistIcon = ({ + className = "", + stroke = "#717179", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default ChecklistIcon; diff --git a/src/assets/svgs/ChevronDownIcon.jsx b/src/assets/svgs/ChevronDownIcon.jsx new file mode 100644 index 0000000..6d329d4 --- /dev/null +++ b/src/assets/svgs/ChevronDownIcon.jsx @@ -0,0 +1,29 @@ +import React from "react"; + +const ChevronDownIcon = ({ + className = "", + stroke = "#D4D4D8", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default ChevronDownIcon; diff --git a/src/assets/svgs/ChevronRightIcon.jsx b/src/assets/svgs/ChevronRightIcon.jsx new file mode 100644 index 0000000..dcdc96e --- /dev/null +++ b/src/assets/svgs/ChevronRightIcon.jsx @@ -0,0 +1,27 @@ +import React from "react"; + +const ChevronRightIcon = ({ + className = "", + fill = "#717179", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default ChevronRightIcon; diff --git a/src/assets/svgs/ChevronUpIcon.jsx b/src/assets/svgs/ChevronUpIcon.jsx new file mode 100644 index 0000000..700e765 --- /dev/null +++ b/src/assets/svgs/ChevronUpIcon.jsx @@ -0,0 +1,32 @@ +import React from "react"; + +const ChevronUpIcon = ({ + className = "", + stroke = "black", + onClick = () => {}, +}) => { + return ( + + + + + + ); +}; + +export default ChevronUpIcon; diff --git a/src/assets/svgs/CircleCheckMarkIcon.jsx b/src/assets/svgs/CircleCheckMarkIcon.jsx new file mode 100644 index 0000000..b9929d1 --- /dev/null +++ b/src/assets/svgs/CircleCheckMarkIcon.jsx @@ -0,0 +1,27 @@ +import React from "react"; + +const CircleCheckMarkIcon = ({ + className = "", + fill = "#38C793", + stroke = "#D4D4D8", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default CircleCheckMarkIcon; diff --git a/src/assets/svgs/CircleCloseIcon.jsx b/src/assets/svgs/CircleCloseIcon.jsx new file mode 100644 index 0000000..eb0721a --- /dev/null +++ b/src/assets/svgs/CircleCloseIcon.jsx @@ -0,0 +1,22 @@ +import React from "react"; + +const CircleCloseIcon = ({ className = "", fill = "#0F1324" }) => { + return ( + + + + ); +}; + +export default CircleCloseIcon; diff --git a/src/assets/svgs/CircleDollarIcon.jsx b/src/assets/svgs/CircleDollarIcon.jsx new file mode 100644 index 0000000..7406667 --- /dev/null +++ b/src/assets/svgs/CircleDollarIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const CircleDollarIcon = ({ + className = "", + stroke = "#717179", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default CircleDollarIcon; diff --git a/src/assets/svgs/CloseIcon.jsx b/src/assets/svgs/CloseIcon.jsx new file mode 100644 index 0000000..ddd54c8 --- /dev/null +++ b/src/assets/svgs/CloseIcon.jsx @@ -0,0 +1,19 @@ +import React from "react"; + +export const CloseIcon = ({ className = "", fill = "#636363" }) => { + return ( + + + + ); +}; diff --git a/src/assets/svgs/CloudUploadIcon.jsx b/src/assets/svgs/CloudUploadIcon.jsx new file mode 100644 index 0000000..bd5f0cb --- /dev/null +++ b/src/assets/svgs/CloudUploadIcon.jsx @@ -0,0 +1,26 @@ +import React from "react"; + +const CloudUploadIcon = ({ + className = "", + fill = "#717179", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default CloudUploadIcon; diff --git a/src/assets/svgs/ColumnIcon.jsx b/src/assets/svgs/ColumnIcon.jsx new file mode 100644 index 0000000..79b53d4 --- /dev/null +++ b/src/assets/svgs/ColumnIcon.jsx @@ -0,0 +1,27 @@ +import React from "react"; + +const ColumnIcon = ({ + className = "", + stroke = "#717179", + fill = "#717179", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default ColumnIcon; diff --git a/src/assets/svgs/CombineIcon.jsx b/src/assets/svgs/CombineIcon.jsx new file mode 100644 index 0000000..a2a1c95 --- /dev/null +++ b/src/assets/svgs/CombineIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const CombineIcon = ({ + className = "", + stroke = "white", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default CombineIcon; diff --git a/src/assets/svgs/ControlIcon.jsx b/src/assets/svgs/ControlIcon.jsx new file mode 100644 index 0000000..192fefa --- /dev/null +++ b/src/assets/svgs/ControlIcon.jsx @@ -0,0 +1,34 @@ +import React from "react"; + +const ControlIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + + + + ); +}; + +export default ControlIcon; diff --git a/src/assets/svgs/CopyIcon.jsx b/src/assets/svgs/CopyIcon.jsx new file mode 100644 index 0000000..027b1d3 --- /dev/null +++ b/src/assets/svgs/CopyIcon.jsx @@ -0,0 +1,16 @@ +import React from "react"; + +export const CopyIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + + + + + + + + ); +}; diff --git a/src/assets/svgs/CsvIcon.jsx b/src/assets/svgs/CsvIcon.jsx new file mode 100644 index 0000000..968a279 --- /dev/null +++ b/src/assets/svgs/CsvIcon.jsx @@ -0,0 +1,153 @@ +import React from "react"; + +const CsvIcon = ({ + className = "", + fill = "#38C793", + stroke = "#D4D4D8", + onClick = () => {}, +}) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default CsvIcon; diff --git a/src/assets/svgs/CycleCountIcon.jsx b/src/assets/svgs/CycleCountIcon.jsx new file mode 100644 index 0000000..0558dce --- /dev/null +++ b/src/assets/svgs/CycleCountIcon.jsx @@ -0,0 +1,41 @@ +import React from "react"; + +const CycleCountIcon = ({ + className = "", + fill = "#18181B", + stroke = "white", + onClick = () => {}, +}) => { + return ( + + + + + + ); +}; + +export default CycleCountIcon; diff --git a/src/assets/svgs/DangerIcon.jsx b/src/assets/svgs/DangerIcon.jsx new file mode 100644 index 0000000..70cd36d --- /dev/null +++ b/src/assets/svgs/DangerIcon.jsx @@ -0,0 +1,13 @@ + + import React from 'react' + + export const DangerIcon = ( { className } ) => { + return ( + + + + + ) + } + + \ No newline at end of file diff --git a/src/assets/svgs/DashIcon.jsx b/src/assets/svgs/DashIcon.jsx new file mode 100644 index 0000000..f45d949 --- /dev/null +++ b/src/assets/svgs/DashIcon.jsx @@ -0,0 +1,24 @@ +import React from "react"; + +const DashIcon = ({ + className = "", + stroke = "black", + fill = "#717179", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default DashIcon; diff --git a/src/assets/svgs/DiagonalArrowIcon.jsx b/src/assets/svgs/DiagonalArrowIcon.jsx new file mode 100644 index 0000000..3b4b214 --- /dev/null +++ b/src/assets/svgs/DiagonalArrowIcon.jsx @@ -0,0 +1,28 @@ +import React from "react"; + +const DiagonalArrowIcon = ({ + className = "", + stroke = "#A1A1A9", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default DiagonalArrowIcon; diff --git a/src/assets/svgs/DotIcon.jsx b/src/assets/svgs/DotIcon.jsx new file mode 100644 index 0000000..b652276 --- /dev/null +++ b/src/assets/svgs/DotIcon.jsx @@ -0,0 +1,59 @@ +import React from "react"; + +const DotIcon = ({ + className = "", + stroke = "black", + fill = "#636363", + onClick = () => {}, +}) => { + return ( + + + + + + + + + + + + ); +}; + +export default DotIcon; diff --git a/src/assets/svgs/DoubleChevronRightIcon.jsx b/src/assets/svgs/DoubleChevronRightIcon.jsx new file mode 100644 index 0000000..ce55a9f --- /dev/null +++ b/src/assets/svgs/DoubleChevronRightIcon.jsx @@ -0,0 +1,26 @@ +import React from "react"; + +const DoubleChevronRightIcon = ({ + className = "", + fill = "#18181B", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default DoubleChevronRightIcon; diff --git a/src/assets/svgs/DownloadIcon.jsx b/src/assets/svgs/DownloadIcon.jsx new file mode 100644 index 0000000..ca2fe0e --- /dev/null +++ b/src/assets/svgs/DownloadIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const DownloadIcon = ({ + className = "", + stroke = "#717179", + onClick = () => {}, +}) => { + return ( + + {/* */} + + + ); +}; + +export default DownloadIcon; diff --git a/src/assets/svgs/DuplicateIcon.jsx b/src/assets/svgs/DuplicateIcon.jsx new file mode 100644 index 0000000..befac2f --- /dev/null +++ b/src/assets/svgs/DuplicateIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const DuplicateIcon = ({ + className = "", + stroke = "#717179", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default DuplicateIcon; diff --git a/src/assets/svgs/EditIcon.jsx b/src/assets/svgs/EditIcon.jsx new file mode 100644 index 0000000..ecb0899 --- /dev/null +++ b/src/assets/svgs/EditIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const EditIcon = ({ + className = "", + stroke = "#717179", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default EditIcon; diff --git a/src/assets/svgs/EditIcon2.jsx b/src/assets/svgs/EditIcon2.jsx new file mode 100644 index 0000000..a3bf0b9 --- /dev/null +++ b/src/assets/svgs/EditIcon2.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const EditIcon2 = ({ + className = "", + stroke = "#717179", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default EditIcon2; diff --git a/src/assets/svgs/ExCircleIcon.jsx b/src/assets/svgs/ExCircleIcon.jsx new file mode 100644 index 0000000..45c6a18 --- /dev/null +++ b/src/assets/svgs/ExCircleIcon.jsx @@ -0,0 +1,29 @@ +import React from "react"; + +const ExCircleIcon = ({ + className = "", + stroke = "#E6483D", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default ExCircleIcon; diff --git a/src/assets/svgs/HamburgerIcon.jsx b/src/assets/svgs/HamburgerIcon.jsx new file mode 100644 index 0000000..9fc2f76 --- /dev/null +++ b/src/assets/svgs/HamburgerIcon.jsx @@ -0,0 +1,29 @@ +import React from "react"; + +const HamburgerIcon = ({ + className = "", + stroke = "white", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default HamburgerIcon; diff --git a/src/assets/svgs/HoldIcon.jsx b/src/assets/svgs/HoldIcon.jsx new file mode 100644 index 0000000..df8ed0f --- /dev/null +++ b/src/assets/svgs/HoldIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const HoldIcon = ({ + className = "", + fill = "#18181B", + stroke = "white", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default HoldIcon; diff --git a/src/assets/svgs/ImportIcon.jsx b/src/assets/svgs/ImportIcon.jsx new file mode 100644 index 0000000..7fbcb35 --- /dev/null +++ b/src/assets/svgs/ImportIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const ImportIcon = ({ + className = "", + fill = "#18181B", + stroke = "#717179", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default ImportIcon; diff --git a/src/assets/svgs/KebabIcon.jsx b/src/assets/svgs/KebabIcon.jsx new file mode 100644 index 0000000..2b4f43e --- /dev/null +++ b/src/assets/svgs/KebabIcon.jsx @@ -0,0 +1,39 @@ +import React from "react"; + +const KebabIcon = ({ className = "", stroke = "#8D8D8D", onClick = () => { } }) => { + return ( + + + + + + ); +}; + +export default KebabIcon; diff --git a/src/assets/svgs/MoveOutIcon.jsx b/src/assets/svgs/MoveOutIcon.jsx new file mode 100644 index 0000000..45160e6 --- /dev/null +++ b/src/assets/svgs/MoveOutIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const MoveOutIcon = ({ + className = "", + stroke = "#717179", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default MoveOutIcon; diff --git a/src/assets/svgs/NarrowUpArrowIcon.jsx b/src/assets/svgs/NarrowUpArrowIcon.jsx new file mode 100644 index 0000000..a9e8e28 --- /dev/null +++ b/src/assets/svgs/NarrowUpArrowIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const NarrowUpArrowIcon = ({ + className = "", + stroke = "#717179", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default NarrowUpArrowIcon; diff --git a/src/assets/svgs/NoFillCircleCheckMarkIcon.jsx b/src/assets/svgs/NoFillCircleCheckMarkIcon.jsx new file mode 100644 index 0000000..9e53a23 --- /dev/null +++ b/src/assets/svgs/NoFillCircleCheckMarkIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const NoFillCircleCheckMarkIcon = ({ + className = "", + stroke = "#2D9F75", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default NoFillCircleCheckMarkIcon; diff --git a/src/assets/svgs/NotesIcon.jsx b/src/assets/svgs/NotesIcon.jsx new file mode 100644 index 0000000..0f18035 --- /dev/null +++ b/src/assets/svgs/NotesIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const NotesIcon = ({ + className = "", + fill = "#18181B", + stroke = "black", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default NotesIcon; diff --git a/src/assets/svgs/PdfIcon.jsx b/src/assets/svgs/PdfIcon.jsx new file mode 100644 index 0000000..2a9c4fb --- /dev/null +++ b/src/assets/svgs/PdfIcon.jsx @@ -0,0 +1,153 @@ +import React from "react"; + +const PdfIcon = ({ + className = "", + fill = "white", + stroke = "#D4D4D8", + onClick = () => {}, +}) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default PdfIcon; diff --git a/src/assets/svgs/PendingIcon.jsx b/src/assets/svgs/PendingIcon.jsx new file mode 100644 index 0000000..e8bb41f --- /dev/null +++ b/src/assets/svgs/PendingIcon.jsx @@ -0,0 +1,37 @@ +import React from "react"; + +const PendingIcon = ({ + className = "", + fill = "#7B1113", + stroke = "#717179", + onClick = () => {}, +}) => { + return ( + + + + + + ); +}; + +export default PendingIcon; diff --git a/src/assets/svgs/PinDownIcon.jsx b/src/assets/svgs/PinDownIcon.jsx new file mode 100644 index 0000000..0d21244 --- /dev/null +++ b/src/assets/svgs/PinDownIcon.jsx @@ -0,0 +1,29 @@ +import React from "react"; + +const PinDownIcon = ({ + className = "", + stroke = "black", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default PinDownIcon; diff --git a/src/assets/svgs/PlusIcon.jsx b/src/assets/svgs/PlusIcon.jsx new file mode 100644 index 0000000..58610dd --- /dev/null +++ b/src/assets/svgs/PlusIcon.jsx @@ -0,0 +1,27 @@ +import React from "react"; + +const PlusIcon = ({ + className = "", + stroke = "black", + fill = "#717179", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default PlusIcon; diff --git a/src/assets/svgs/PrintIcon.jsx b/src/assets/svgs/PrintIcon.jsx new file mode 100644 index 0000000..e472657 --- /dev/null +++ b/src/assets/svgs/PrintIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const PrintIcon = ({ + className = "", + stroke = "#717179", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default PrintIcon; diff --git a/src/assets/svgs/PurgeIcon.jsx b/src/assets/svgs/PurgeIcon.jsx new file mode 100644 index 0000000..4f72fd5 --- /dev/null +++ b/src/assets/svgs/PurgeIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const PurgeIcon = ({ + className = "", + fill = "#18181B", + stroke = "white", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default PurgeIcon; diff --git a/src/assets/svgs/QaulityLogo.jsx b/src/assets/svgs/QaulityLogo.jsx new file mode 100644 index 0000000..0eade66 --- /dev/null +++ b/src/assets/svgs/QaulityLogo.jsx @@ -0,0 +1,39 @@ +import React from "react"; + +const QaulityLogo = ({ className = "", onClick = () => {} }) => { + return ( + + + + + + + + + + ); +}; + +export default QaulityLogo; diff --git a/src/assets/svgs/RotateIcon.jsx b/src/assets/svgs/RotateIcon.jsx new file mode 100644 index 0000000..17aecc3 --- /dev/null +++ b/src/assets/svgs/RotateIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const RotateIcon = ({ + className = "", + stroke = "white", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default RotateIcon; diff --git a/src/assets/svgs/SmallPinIcon.jsx b/src/assets/svgs/SmallPinIcon.jsx new file mode 100644 index 0000000..48633d6 --- /dev/null +++ b/src/assets/svgs/SmallPinIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const SmallPinIcon = ({ + className = "", + stroke = "#F2AE40", + onClick = () => {}, +}) => { + return ( + + + + + ); +}; + +export default SmallPinIcon; diff --git a/src/assets/svgs/SortIcon.jsx b/src/assets/svgs/SortIcon.jsx new file mode 100644 index 0000000..efa654b --- /dev/null +++ b/src/assets/svgs/SortIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const SortIcon = ({ + className = "", + stroke = "#717179", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default SortIcon; diff --git a/src/assets/svgs/Spinner.jsx b/src/assets/svgs/Spinner.jsx new file mode 100644 index 0000000..20c7a65 --- /dev/null +++ b/src/assets/svgs/Spinner.jsx @@ -0,0 +1,21 @@ + + import React, { useId } from "react"; + import MoonLoader from "react-spinners/MoonLoader"; + +const override = { + borderColor: "red", +}; + +export const Spinner = ({ size = 20, color = "#ffffff" }) => { + const id = useId(); + return ( + + ); +}; diff --git a/src/assets/svgs/SplitIcon.jsx b/src/assets/svgs/SplitIcon.jsx new file mode 100644 index 0000000..de53d6e --- /dev/null +++ b/src/assets/svgs/SplitIcon.jsx @@ -0,0 +1,45 @@ +import React from "react"; + +const SplitIcon = ({ + className = "", + stroke = "#717179", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + + + + ); +}; + +export default SplitIcon; diff --git a/src/assets/svgs/SubmittedIcon.jsx b/src/assets/svgs/SubmittedIcon.jsx new file mode 100644 index 0000000..e8617e0 --- /dev/null +++ b/src/assets/svgs/SubmittedIcon.jsx @@ -0,0 +1,47 @@ +import React from "react"; + +const SubmittedIcon = ({ + className = "", + fill = "#7B1113", + stroke = "#717179", + onClick = () => {}, +}) => { + return ( + + + + + + + + + ); +}; + +export default SubmittedIcon; diff --git a/src/assets/svgs/TrashIcon.jsx b/src/assets/svgs/TrashIcon.jsx new file mode 100644 index 0000000..df7c2b7 --- /dev/null +++ b/src/assets/svgs/TrashIcon.jsx @@ -0,0 +1,24 @@ +import React from "react"; + +const TrashIcon = ({ className = "", fill = "#A8A8A8", onClick = () => { } }) => { + return ( + + + + ); +}; + +export default TrashIcon; diff --git a/src/assets/svgs/UpdateIcon.jsx b/src/assets/svgs/UpdateIcon.jsx new file mode 100644 index 0000000..b1ad6cf --- /dev/null +++ b/src/assets/svgs/UpdateIcon.jsx @@ -0,0 +1,30 @@ +import React from "react"; + +const UpdateIcon = ({ + className = "", + stroke = "#717179", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default UpdateIcon; diff --git a/src/assets/svgs/VoidIcon.jsx b/src/assets/svgs/VoidIcon.jsx new file mode 100644 index 0000000..55237ec --- /dev/null +++ b/src/assets/svgs/VoidIcon.jsx @@ -0,0 +1,31 @@ +import React from "react"; + +const VoidIcon = ({ + className = "", + stroke = "#717179", + fill = "none", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default VoidIcon; diff --git a/src/assets/svgs/VoidedIcon.jsx b/src/assets/svgs/VoidedIcon.jsx new file mode 100644 index 0000000..38ade12 --- /dev/null +++ b/src/assets/svgs/VoidedIcon.jsx @@ -0,0 +1,31 @@ +import React from "react"; + +const VoidedIcon = ({ + className = "", + fill = "#A1A1A9", + stroke = "#717179", + onClick = () => {}, +}) => { + return ( + + + + + ); +}; + +export default VoidedIcon; diff --git a/src/assets/svgs/WarningIcon.jsx b/src/assets/svgs/WarningIcon.jsx new file mode 100644 index 0000000..dc6574c --- /dev/null +++ b/src/assets/svgs/WarningIcon.jsx @@ -0,0 +1,28 @@ +import React from "react"; + +const WarningIcon = ({ + className = "", + stroke = "black", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default WarningIcon; diff --git a/src/assets/svgs/XCloseIcon.jsx b/src/assets/svgs/XCloseIcon.jsx new file mode 100644 index 0000000..f16b397 --- /dev/null +++ b/src/assets/svgs/XCloseIcon.jsx @@ -0,0 +1,28 @@ +import React from "react"; + +const XCloseIcon = ({ + className = "", + stroke = "#717179", + onClick = () => {}, +}) => { + return ( + + + + ); +}; + +export default XCloseIcon; diff --git a/src/assets/svgs/index.js b/src/assets/svgs/index.js new file mode 100644 index 0000000..c42de47 --- /dev/null +++ b/src/assets/svgs/index.js @@ -0,0 +1,57 @@ +export { CloseIcon } from "./CloseIcon"; +export { DangerIcon } from "./DangerIcon"; +export { Spinner } from "./Spinner"; +export { CaretLeft } from "./CaretLeft"; +export { default as AvatarIcon } from "./AvatarIcon"; +export { default as ChevronUpIcon } from "./ChevronUpIcon"; +export { default as EditIcon } from "./EditIcon"; +export { default as QaulityLogo } from "./QaulityLogo"; +export { default as ChevronDownIcon } from "./ChevronDownIcon"; +export { default as SmallPinIcon } from "./SmallPinIcon"; +export { default as BigPinIcon } from "./BigPinIcon"; +export { default as PinDownIcon } from "./PinDownIcon"; +export { default as HamburgerIcon } from "./HamburgerIcon"; +export { default as DoubleChevronRightIcon } from "./DoubleChevronRightIcon"; +export { default as ChevronRightIcon } from "./ChevronRightIcon"; +export { default as ExCircleIcon } from "./ExCircleIcon"; +export { default as DiagonalArrowIcon } from "./DiagonalArrowIcon"; +export { default as PurgeIcon } from "./PurgeIcon"; +export { default as HoldIcon } from "./HoldIcon"; +export { default as CycleCountIcon } from "./CycleCountIcon"; +export { default as ImportIcon } from "./ImportIcon"; +export { default as NotesIcon } from "./NotesIcon"; +export { default as CircleCloseIcon } from "./CircleCloseIcon"; +export { default as KebabIcon } from "./KebabIcon"; +export { default as TrashIcon } from "./TrashIcon"; +export { default as ControlIcon } from "./ControlIcon"; +export { default as CloudUploadIcon } from "./CloudUploadIcon"; +export { default as PdfIcon } from "./PdfIcon"; +export { default as WarningIcon } from "./WarningIcon"; +export { default as ChecklistIcon } from "./ChecklistIcon"; +export { default as AddressbookIcon } from "./AddressbookIcon"; +export { default as DownloadIcon } from "./DownloadIcon"; +export { default as CsvIcon } from "./CsvIcon"; +export { default as CircleCheckMarkIcon } from "./CircleCheckMarkIcon"; +export { default as DashIcon } from "./DashIcon"; +export { default as PlusIcon } from "./PlusIcon"; +export { default as EditIcon2 } from "./EditIcon2"; +export { default as NoFillCircleCheckMarkIcon } from "./NoFillCircleCheckMarkIcon"; +export { default as PrintIcon } from "./PrintIcon"; +export { default as CircleDollarIcon } from "./CircleDollarIcon"; +export { default as UpdateIcon } from "./UpdateIcon"; +export { default as NarrowUpArrowIcon } from "./NarrowUpArrowIcon"; +export { default as RotateIcon } from "./RotateIcon"; +export { default as DuplicateIcon } from "./DuplicateIcon"; +export { default as VoidIcon } from "./VoidIcon"; +export { default as SplitIcon } from "./SplitIcon"; +export { default as MoveOutIcon } from "./MoveOutIcon"; +export { default as SubmittedIcon } from "./SubmittedIcon"; +export { default as VoidedIcon } from "./VoidedIcon"; +export { default as PendingIcon } from "./PendingIcon"; +export { default as CombineIcon } from "./CombineIcon"; +export { default as CheckIcon } from "./CheckIcon"; +export { default as AwaitIcon } from "./AwaitIcon"; +export { default as XCloseIcon } from "./XCloseIcon"; +export { default as ColumnIcon } from "./ColumnIcon"; +export { default as SortIcon } from "./SortIcon"; +export { default as DotIcon } from "./DotIcon"; diff --git a/src/components/AddButton/AddButton.jsx b/src/components/AddButton/AddButton.jsx new file mode 100644 index 0000000..4b07c9a --- /dev/null +++ b/src/components/AddButton/AddButton.jsx @@ -0,0 +1,60 @@ +import React, { useId, useState } from "react"; +import classes from "./AddButton.module.css"; +import MoonLoader from "react-spinners/MoonLoader"; + +const AddButton = ({ + onClick, + children = "Add New", + showPlus = true, + className, + showChildren = true, + loaderclasses, + color = "#ffffff", + loading = false, + disabled = false, + icon = null, + title, +}) => { + const override = { + borderColor: "#ffffff", + }; + const id = useId(); + const [animate, setAnimate] = useState(false); + + const onClickHandle = () => { + if (onClick) { + onClick(); + } + setAnimate(true); + }; + // const classes = ` after:bg-[#90EE90] after:block after:absolute after:pt-[300%] after:pl-[350%] after:!ml-[-1.25rem] after:mt-[-120%] after:opacity-0 after:transition-all active:after:p-0 active:after:m-0 active:after:opacity-100 `; + return ( + + ); +}; + +export default AddButton; diff --git a/src/components/AddButton/AddButton.module.css b/src/components/AddButton/AddButton.module.css new file mode 100644 index 0000000..d34a311 --- /dev/null +++ b/src/components/AddButton/AddButton.module.css @@ -0,0 +1,32 @@ +.button { + position: relative; + /* border: none; */ + color: #ffffff; + text-align: center; + -webkit-transition-duration: 0.4s; /* Safari */ + transition-duration: 0.4s; + text-decoration: none; + overflow: hidden; + cursor: pointer; + /* background-color: #7B1113; */ +} +.button:after { + content: ""; + background-color: #7b1113; + /* background: #4f46e5; */ + display: block; + position: absolute; + padding-top: 300%; + padding-left: 350%; + margin-left: -20px !important; + margin-top: -120%; + opacity: 0; + transition: all 0.8s; +} + +.button:active:after { + padding: 0; + margin: 0; + opacity: 1; + transition: 0s; +} diff --git a/src/components/AddButton/index.js b/src/components/AddButton/index.js new file mode 100644 index 0000000..f2c4a1d --- /dev/null +++ b/src/components/AddButton/index.js @@ -0,0 +1 @@ +export { default as AddButton } from "./AddButton"; diff --git a/src/components/DropdownOptions/DropdownOption/DropdownOption.jsx b/src/components/DropdownOptions/DropdownOption/DropdownOption.jsx new file mode 100644 index 0000000..3dd66c1 --- /dev/null +++ b/src/components/DropdownOptions/DropdownOption/DropdownOption.jsx @@ -0,0 +1,24 @@ +import React from "react"; + +const DropdownOption = ({ + icon, + onClick = () => {}, + name, + style = {}, + className = "", +}) => { + return ( +
{ + onClick(e); + }} + > + {icon && {icon}} + {name && {name}} +
+ ); +}; + +export default DropdownOption; diff --git a/src/components/DropdownOptions/DropdownOption/index.js b/src/components/DropdownOptions/DropdownOption/index.js new file mode 100644 index 0000000..ea35edb --- /dev/null +++ b/src/components/DropdownOptions/DropdownOption/index.js @@ -0,0 +1,3 @@ +import { lazy } from "react"; + +export const DropdownOption = lazy(() => import("./DropdownOption")); diff --git a/src/components/DropdownOptions/DropdownOptions.jsx b/src/components/DropdownOptions/DropdownOptions.jsx new file mode 100644 index 0000000..e25f67e --- /dev/null +++ b/src/components/DropdownOptions/DropdownOptions.jsx @@ -0,0 +1,29 @@ +import React from "react"; +import { KebabIcon } from "Assets/svgs"; + +const DropdownOptions = ({ + icon, + children, + childrenWrapperClass = "", + iconWrapperClass = "", + className = "", + style = {}, +}) => { + return ( +
+ + +
+ ); +}; + +export default DropdownOptions; diff --git a/src/components/DropdownOptions/index.js b/src/components/DropdownOptions/index.js new file mode 100644 index 0000000..d1b5467 --- /dev/null +++ b/src/components/DropdownOptions/index.js @@ -0,0 +1,4 @@ +import { lazy } from "react"; + +export const DropdownOptions = lazy(() => import("./DropdownOptions")); +export { DropdownOption } from "./DropdownOption"; diff --git a/src/components/MkdInput/MkdInput.css b/src/components/MkdInput/MkdInput.css new file mode 100644 index 0000000..7fcc021 --- /dev/null +++ b/src/components/MkdInput/MkdInput.css @@ -0,0 +1,145 @@ +.toggleClass.react-toggle--checked .react-toggle-track { + background-color: #7b1113; +} + +.react-toggle { + touch-action: pan-x; + + display: inline-block; + position: relative; + cursor: pointer; + background-color: transparent; + border: 0; + padding: 0; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + -webkit-tap-highlight-color: #ffffff; + -webkit-tap-highlight-color: transparent; +} + +.react-toggle-screenreader-only { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +.react-toggle--disabled { + cursor: not-allowed; + opacity: 0.5; + -webkit-transition: opacity 0.25s; + transition: opacity 0.25s; +} + +.react-toggle-track { + width: 50px; + height: 24px; + padding: 0; + border-radius: 30px; + background-color: #d4d4d8; + -webkit-transition: all 0.2s ease; + -moz-transition: all 0.2s ease; + transition: all 0.2s ease; +} + +.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track { + /* background-color: #000000; */ +} + +.react-toggle--checked .react-toggle-track { + background-color: #7b1113; +} + +.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track { + background-color: #7b1113; +} + +.react-toggle-track-check { + position: absolute; + width: 14px; + height: 10px; + top: 0px; + bottom: 0px; + margin-top: auto; + margin-bottom: auto; + line-height: 0; + left: 8px; + opacity: 0; + -webkit-transition: opacity 0.25s ease; + -moz-transition: opacity 0.25s ease; + transition: opacity 0.25s ease; +} + +.react-toggle--checked .react-toggle-track-check { + opacity: 1; + -webkit-transition: opacity 0.25s ease; + -moz-transition: opacity 0.25s ease; + transition: opacity 0.25s ease; +} + +.react-toggle-track-x { + position: absolute; + width: 10px; + height: 10px; + top: 0px; + bottom: 0px; + margin-top: auto; + margin-bottom: auto; + line-height: 0; + right: 10px; + opacity: 1; + -webkit-transition: opacity 0.25s ease; + -moz-transition: opacity 0.25s ease; + transition: opacity 0.25s ease; +} + +.react-toggle--checked .react-toggle-track-x { + opacity: 0; +} + +.react-toggle-thumb { + transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1) 0ms; + position: absolute; + top: 1px; + left: 1px; + width: 22px; + height: 22px; + border: 1px solid #4d4d4d; + border-radius: 50%; + background-color: #fafafa; + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + + -webkit-transition: all 0.25s ease; + -moz-transition: all 0.25s ease; + transition: all 0.25s ease; +} + +.react-toggle--checked .react-toggle-thumb { + left: 27px; + border-color: #7b1113; +} + +.react-toggle--focus .react-toggle-thumb { + -webkit-box-shadow: 0px 0px 3px 2px #7b1113; + -moz-box-shadow: 0px 0px 3px 2px #7b1113; + box-shadow: 0px 0px 2px 3px #7b1113; +} + +.react-toggle:active:not(.react-toggle--disabled) .react-toggle-thumb { + -webkit-box-shadow: 0px 0px 5px 5px #7b1113; + -moz-box-shadow: 0px 0px 5px 5px #7b1113; + box-shadow: 0px 0px 5px 5px #7b1113; +} diff --git a/src/components/MkdInput/MkdInput.jsx b/src/components/MkdInput/MkdInput.jsx new file mode 100644 index 0000000..78db34f --- /dev/null +++ b/src/components/MkdInput/MkdInput.jsx @@ -0,0 +1,209 @@ +import React, { useId } from "react"; +import { StringCaser } from "Utils/utils"; +import Toggle from "react-toggle"; +import "./MkdInput.css"; +import { SkeletonLoader } from "Components/Skeleton"; + +const MkdInput = ({ + type = "text", + page, + cols = "30", + rows = "50", + name, + label, + errors = null, + register = () => ({}), + className, + placeholder, + options = [], + mapping = null, + disabled = false, + value = null, + onChange, + loading = false, + required = false, +}) => { + const uniqueId = useId(); + return ( + <> +
+ {["radio", "checkbox", "color", "toggle"].includes(type) ? null : ( + <> + {label && ( + + )} + + )} + {loading ? ( + + ) : type === "textarea" ? ( + <> + + + ) : ["radio", "checkbox", "color", "toggle"].includes(type) ? ( +
+ {["toggle"].includes(type) ? ( + + ) : ( + // + + )} + +
+ ) : type === "dropdown" || type === "select" ? ( + + ) : type === "mapping" ? ( + <> + {mapping ? ( + + ) : ( + `Please Pass the mapping e.g {key:value}` + )} + + ) : ( + + )} + + {errors && errors[name] && ( +

+ {StringCaser(errors[name]?.message, { + casetype: "capitalize", + separator: " ", + })} +

+ )} +
+ + ); +}; + +export default MkdInput; diff --git a/src/components/MkdInput/MkdInput.module.css b/src/components/MkdInput/MkdInput.module.css new file mode 100644 index 0000000..b940f44 --- /dev/null +++ b/src/components/MkdInput/MkdInput.module.css @@ -0,0 +1,145 @@ +.toggleClass.react-toggle--checked .react-toggle-track { + background-color: #7b1113; +} + +.react-toggle { + touch-action: pan-x; + + display: inline-block; + position: relative; + cursor: pointer; + background-color: transparent; + border: 0; + padding: 0; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-tap-highlight-color: transparent; +} + +.react-toggle-screenreader-only { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +.react-toggle--disabled { + cursor: not-allowed; + opacity: 0.5; + -webkit-transition: opacity 0.25s; + transition: opacity 0.25s; +} + +.react-toggle-track { + width: 50px; + height: 24px; + padding: 0; + border-radius: 30px; + background-color: #4d4d4d; + -webkit-transition: all 0.2s ease; + -moz-transition: all 0.2s ease; + transition: all 0.2s ease; +} + +.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track { + background-color: #000000; +} + +.react-toggle--checked .react-toggle-track { + background-color: #19ab27; +} + +.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track { + background-color: #128d15; +} + +.react-toggle-track-check { + position: absolute; + width: 14px; + height: 10px; + top: 0px; + bottom: 0px; + margin-top: auto; + margin-bottom: auto; + line-height: 0; + left: 8px; + opacity: 0; + -webkit-transition: opacity 0.25s ease; + -moz-transition: opacity 0.25s ease; + transition: opacity 0.25s ease; +} + +.react-toggle--checked .react-toggle-track-check { + opacity: 1; + -webkit-transition: opacity 0.25s ease; + -moz-transition: opacity 0.25s ease; + transition: opacity 0.25s ease; +} + +.react-toggle-track-x { + position: absolute; + width: 10px; + height: 10px; + top: 0px; + bottom: 0px; + margin-top: auto; + margin-bottom: auto; + line-height: 0; + right: 10px; + opacity: 1; + -webkit-transition: opacity 0.25s ease; + -moz-transition: opacity 0.25s ease; + transition: opacity 0.25s ease; +} + +.react-toggle--checked .react-toggle-track-x { + opacity: 0; +} + +.react-toggle-thumb { + transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1) 0ms; + position: absolute; + top: 1px; + left: 1px; + width: 22px; + height: 22px; + border: 1px solid #4d4d4d; + border-radius: 50%; + background-color: #fafafa; + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + + -webkit-transition: all 0.25s ease; + -moz-transition: all 0.25s ease; + transition: all 0.25s ease; +} + +.react-toggle--checked .react-toggle-thumb { + left: 27px; + border-color: #19ab27; +} + +.react-toggle--focus .react-toggle-thumb { + -webkit-box-shadow: 0px 0px 3px 2px #0099e0; + -moz-box-shadow: 0px 0px 3px 2px #0099e0; + box-shadow: 0px 0px 2px 3px #0099e0; +} + +.react-toggle:active:not(.react-toggle--disabled) .react-toggle-thumb { + -webkit-box-shadow: 0px 0px 5px 5px #0099e0; + -moz-box-shadow: 0px 0px 5px 5px #0099e0; + box-shadow: 0px 0px 5px 5px #0099e0; +} diff --git a/src/components/MkdInput/index.js b/src/components/MkdInput/index.js new file mode 100644 index 0000000..6a5f779 --- /dev/null +++ b/src/components/MkdInput/index.js @@ -0,0 +1,3 @@ + + export { default as MkdInput } from "./MkdInput"; + \ No newline at end of file diff --git a/src/components/MkdListTable/MkdListTable.css b/src/components/MkdListTable/MkdListTable.css new file mode 100644 index 0000000..a052ecc --- /dev/null +++ b/src/components/MkdListTable/MkdListTable.css @@ -0,0 +1,42 @@ +table thead { + border-top-left-radius: 0.625rem !important; + border-top-right-radius: 0.625rem !important; +} +table thead tr { + border-top-left-radius: 0.625rem !important; + border-top-right-radius: 0.625rem !important; + background-color: #f4f4f5; +} +tbody tr:last-child { + border-bottom: none; +} +table thead tr:first-child th:first-child { + border-left: 0.0313rem solid #e5e7eb; + border-top: 0.0313rem solid #e5e7eb; + border-top-left-radius: 0.625rem !important; +} +table thead tr:first-child th:last-child { + border-right: 0.0313rem solid #e5e7eb; + border-top: 0.0313rem solid #e5e7eb; + border-top-right-radius: 0.625rem !important; +} +table thead tr:first-child th { + border-top: 0.0313rem solid #e5e7eb; +} +table tbody tr:last-child td:first-child { + border-bottom-left-radius: 0.625rem !important; +} +table tbody tr:last-child td:last-child { + border-bottom-right-radius: 0.625rem !important; +} + +table tbody tr td:first-child { + border-left: 0.0313rem solid #e5e7eb; +} +table tbody tr td { + border-right: 0.0313rem solid #e5e7eb; +} + +.no-data-found { + filter: grayscale(10); +} diff --git a/src/components/MkdListTable/MkdListTable.jsx b/src/components/MkdListTable/MkdListTable.jsx new file mode 100644 index 0000000..2e736b5 --- /dev/null +++ b/src/components/MkdListTable/MkdListTable.jsx @@ -0,0 +1,339 @@ +import React, { Fragment } from "react"; +import { useNavigate } from "react-router-dom"; +import { DotIcon, KebabIcon, NarrowUpArrowIcon, Spinner } from "Assets/svgs"; +import { SkeletonLoader } from "Components/Skeleton"; +import { NoDataFoundImg } from "Assets/images"; +import MkdListTableSelectRow from "./MkdListTableSelectRow"; +import MkdListTableRightActionPanel from "./MkdListTableRightActionPanel"; +import MkdListTableRow from "./MkdListTableRow"; + +const MkdListTable = ({ + table, + tableTitle, + onSort, + loading, + columns = [], + actions, + actionPostion = [], + tableRole, + deleteItem, + deleteLoading, + actionId = "id", + showDeleteModal, + currentTableData = [], + setShowDeleteModal, + handleTableCellChange, + setSelectedItems, + allowEditing, + useImage = true, + columnData = null, + setColumns = null, + setColumnData = null, + allowSortColumns = true, + onPopoverStateChange = null, + popoverShown = false, +}) => { + const [deleteId, setIdToDelete] = React.useState(null); + const [isOneOrMoreRowSelected, setIsOneOrMoreRowSelected] = + React.useState(false); + const [areAllRowsSelected, setAreAllRowsSelected] = React.useState(false); + const [selectedIds, setSelectedIds] = React.useState([]); + const [dragging, setDragging] = React.useState(false); + const [fromKey, setFromKey] = React.useState(null); + const [toKey, setToKey] = React.useState(null); + + function handleSelectRow(id) { + setIsOneOrMoreRowSelected(true); + const tempIds = selectedIds; + + if (actions?.select?.multiple) { + if (tempIds.includes(id)) { + const newIds = tempIds.filter((selectedId) => selectedId !== id); + setSelectedIds(() => [...newIds]); + setSelectedItems(newIds); + } else { + const newIds = [...tempIds, id]; + setSelectedIds(() => [...newIds]); + setSelectedItems(newIds); + } + } else { + if (tempIds.includes(id)) { + const newIds = tempIds.filter((selectedId) => selectedId !== id); + setSelectedIds(() => [...newIds]); + setSelectedItems(newIds); + } else { + const newIds = [id]; + setSelectedIds(() => [...newIds]); + setSelectedItems(newIds); + } + } + console.log(id); + } + + const handleSelectAll = () => { + setAreAllRowsSelected((prevSelectAll) => !prevSelectAll); + if (!areAllRowsSelected) { + const allIds = currentTableData.map((item) => item[actionId]); + setSelectedIds(allIds); + setSelectedItems(allIds); + } else { + setSelectedIds([]); + setSelectedItems([]); + } + }; + + const handleDeleteAll = async (id) => { + setShowDeleteModal(true); + setIdToDelete(id); + }; + + const navigate = useNavigate(); + + const setDeleteId = async (id) => { + console.log("id >>", id); + setShowDeleteModal(true); + setIdToDelete(id); + }; + + const onDragStart = (e, key) => { + if (!allowSortColumns) return; + // e.preventDefault(); + // console.log("onDragStart"); + setFromKey(key); + setDragging(true); + }; + const onDrop = (e) => { + if (!allowSortColumns) return; + e.preventDefault(); + if (fromKey && toKey && fromKey != toKey) { + const tempColumns = [...columns]; + const fromColumn = tempColumns[fromKey]; + const toColumn = tempColumns[toKey]; + + tempColumns.splice(fromKey, 1); + tempColumns.splice(toKey, 0, fromColumn); + if (setColumns) { + setColumns(() => tempColumns); + } + } + setToKey(null); + setFromKey(null); + setDragging(false); + }; + const onDragOver = (e, key) => { + if (!allowSortColumns) return; + e.preventDefault(); + + setToKey(key); + // if (fromKey != key) { + // } + }; + const onDragEnter = (e) => { + if (!allowSortColumns) return; + e.preventDefault(); + }; + const onDragEnd = (e) => { + if (!allowSortColumns) return; + e.preventDefault(); + setToKey(null); + setFromKey(null); + // console.log("onDragEnd"); + + setDragging(false); + }; + const onDragLeave = (e) => { + if (!allowSortColumns) return; + e.preventDefault(); + setToKey(null); + // setFromKey(null); + }; + + React.useEffect(() => { + if (selectedIds.length <= 0) { + setIsOneOrMoreRowSelected(false); + setAreAllRowsSelected(false); + } + if (selectedIds.length === currentTableData?.length) { + setAreAllRowsSelected(true); + setIsOneOrMoreRowSelected(true); + } + if ( + selectedIds.length < currentTableData?.length && + selectedIds.length > 0 + ) { + setAreAllRowsSelected(false); + } + }, [selectedIds, currentTableData]); + // console.log("currentTableData"); + // console.log(currentTableData); + // console.log(columns) + return ( + <> +
+ + + {/* BR */} +
+ {(loading && useImage) || + (loading && !columns?.length) || + (loading && !currentTableData?.length) ? ( +
+ +
+ ) : columns?.length && currentTableData?.length ? ( + <> + {columns?.map((cell, cellIndex) => { + if ( + !["row", ""].includes(cell?.accessor) && + cell?.selected_column + ) { + return ( +
+
onDragStart(e, cellIndex)} + onDragEnd={onDragEnd} + onDragOver={(e) => onDragOver(e, cellIndex)} + onDragLeave={(e) => onDragLeave(e)} + onDrop={(e) => onDrop(e)} + className={`flex !h-[2.65rem] !max-h-[2.65rem] !min-h-[2.65rem] w-full !min-w-full max-w-fit items-center justify-start gap-2 px-[.75rem] py-[.5rem] ${ + allowSortColumns && dragging + ? "cursor-grabbing" + : cell?.isSorted + ? "cursor-pointer" + : "" + } ${ + toKey == cellIndex + ? "bg-primary-light" + : "bg-weak-100" + } `} + > +
onSort(cellIndex) : undefined + } + > +
+ {cell.header} +
+ + {cell.isSorted ? ( + + ) : ( + "" + )} + +
+ {allowSortColumns ? ( + + ) : null} +
+ + {currentTableData?.map((row, rowIndex) => { + return ( + + ); + })} +
+ ); + } + })} + + ) : !loading && !currentTableData?.length ? ( +
+
+
+ {useImage ? ( + + ) : ( + <>No Data + )} +
+
+
+ ) : null} +
+ + +
+ + ); +}; + +export default MkdListTable; diff --git a/src/components/MkdListTable/MkdListTableBindOperations.jsx b/src/components/MkdListTable/MkdListTableBindOperations.jsx new file mode 100644 index 0000000..a499d7c --- /dev/null +++ b/src/components/MkdListTable/MkdListTableBindOperations.jsx @@ -0,0 +1,104 @@ +export const operations = { + EQUAL: "eq", + NOT_EQUAL: "neq", + IS_NULL: "isn", + IS_NOT_NULL: "isnn", + CONTAINS: "cs", + START_WITH: "sw", + END_WITH: "ew", + LESS_THAN: "lt", + GREATER_THAN: "gt", +}; + +export const runOperation = (row, column, operator, value) => { + switch (operator) { + case operations.EQUAL: + // TO DO + // return runEqualOperation(row, column, value); + case operations.NOT_EQUAL: + // TO DO + // return runNotEqualOperation(row, column, value); + case operations.IS_NULL: + // TO DO + // return runIsNullOperation(row, column, value); + case operations.IS_NOT_NULL: + // TO DO + // return runIsNotNullOperation(row, column, value); + case operations.CONTAINS: + // TO DO + // return runContainsOperation(row, column, value); + case operations.START_WITH: + // TO DO + // return runStartWithOperation(row, column, value); + case operations.END_WITH: + // TO DO + // return runEndWithOperation(row, column, value); + case operations.GREATER_THAN: + // TO DO + // return runGreaterThanOperation(row, column, value); + case operations.LESS_THAN: + // TO DO + // return runLessThanOperation(row, column, value); + } +}; +export const logicalOR = (action, row) => { + if ( + !Array.isArray(action?.bind?.column) || + !Array.isArray(action?.bind?.ifValue) + ) { + return false; + } + if (action?.bind?.column?.length !== action?.bind?.ifValue?.length) { + return false; + } + + const result = action?.bind?.ifValue.map((value, index) => + runOperation( + row, + action?.bind?.column[index], + action?.bind?.operator, + value + ) + ); + return result.some((res) => res === true); +}; + +export const logicalAND = (action, row) => { + if ( + !Array.isArray(action?.bind?.column) || + !Array.isArray(action?.bind?.ifValue) + ) { + return false; + } + if (action?.bind?.column?.length !== action?.bind?.ifValue?.length) { + return false; + } + + const result = action?.bind?.ifValue.map((value, index) => + runOperation( + row, + action?.bind?.column[index], + action?.bind?.operator, + value + ) + ); + return result.every((res) => res === true); +}; + +export const processBind = (action, row) => { + if (action?.bind?.logic) { + switch (action?.bind?.logic) { + case "or": + return logicalOR(action, row); + case "and": + return logicalAND(action, row); + } + } else { + return runOperation( + row, + action?.bind?.column, + action?.bind?.operator, + action?.bind?.ifValue + ); + } +}; diff --git a/src/components/MkdListTable/MkdListTableHead.jsx b/src/components/MkdListTable/MkdListTableHead.jsx new file mode 100644 index 0000000..50e1e2f --- /dev/null +++ b/src/components/MkdListTable/MkdListTableHead.jsx @@ -0,0 +1,52 @@ +import React from "react"; +import { NarrowUpArrowIcon } from "Assets/svgs"; +import { SkeletonLoader } from "Components/Skeleton"; + +const MkdListTableHead = ({ onSort, columns }) => { + return ( + <> + + {!columns?.length ? ( + + + + ) : null} + {columns.map((column, i) => { + if (column?.accessor !== "" && column?.selected_column) { + return ( + onSort(i) : undefined} + > +
+ {column.header} + + {column.isSorted ? ( + + ) : ( + "" + )} + +
+ + ); + } + })} + + + ); +}; + +export default MkdListTableHead; diff --git a/src/components/MkdListTable/MkdListTableRightActionPanel.jsx b/src/components/MkdListTable/MkdListTableRightActionPanel.jsx new file mode 100644 index 0000000..1ac3fcb --- /dev/null +++ b/src/components/MkdListTable/MkdListTableRightActionPanel.jsx @@ -0,0 +1,96 @@ +import React, { Fragment } from "react"; +import MkdListTableRowDropdown from "./MkdListTableRowDropdown"; +import MkdListTableRowButtons from "./MkdListTableRowButtons"; + +const MkdListTableRightActionPanel = ({ + table, + loading, + columns = [], + actions, + actionPostion = [], + tableRole, + deleteItem, + deleteLoading, + actionId = "id", + showDeleteModal, + currentTableData = [], + setShowDeleteModal, +}) => { + const [deleteId, setIdToDelete] = React.useState(null); + + const setDeleteId = async (id) => { + console.log("id >>", id); + setShowDeleteModal(true); + setIdToDelete(id); + }; + return ( + + {!loading && currentTableData.length && columns.length ? ( + <> + {(columns.find((item) => item.accessor === "") && + actions?.delete?.show) || + Object.keys(actions).filter( + (key) => + actions[key]?.show && + actions[key]?.locations && + actions[key]?.locations?.length && + (actions[key]?.locations?.includes("dropdown") || + actions[key]?.locations?.includes("buttons")) + )?.length ? ( +
+
+
+ +
+ {currentTableData?.map((rowData, rowDataIndex) => { + return ( +
+ {/* // key={rowDataIndex} + // className="!h-[3rem] !max-h-[3rem] !min-h-[3rem] w-fit border-b" */} + {actionPostion?.includes("dropdown") ? ( + <> + {/* */} + + + ) : null} + {actionPostion?.includes("buttons") ? ( + <> + + + ) : null} +
+ ); + })} +
+
+
+ ) : null} + + ) : null} +
+ ); +}; + +export default MkdListTableRightActionPanel; +// [ +// actions?.view?.show, +// actions?.edit?.show, +// actions?.delete?.show, +// actions?.status?.show, +// ].includes(true) || diff --git a/src/components/MkdListTable/MkdListTableRow.jsx b/src/components/MkdListTable/MkdListTableRow.jsx new file mode 100644 index 0000000..5b3118c --- /dev/null +++ b/src/components/MkdListTable/MkdListTableRow.jsx @@ -0,0 +1,296 @@ +import React from "react"; +import { MdPhoto } from "react-icons/md"; +import { MkdPopover } from "Components/MkdPopover"; +import { NotesIcon } from "Assets/svgs"; + +import { truncate, processList, mappingValues } from "Utils/utils"; +import { GlobalContext } from "Context/Global"; +import { AuthContext } from "Context/Auth"; +import { SkeletonLoader } from "Components/Skeleton"; + +const statusNames = { + status: "status", + verify: "verify", + receipt_status: "receipt_status", +}; + +const MkdListTableRow = ({ + column = null, + actions, + tableRole = "", + actionPostion = [], + actionId = "id", + handleTableCellChange, + selectedIds = [], + handleSelectRow, + columnIndex, + allowEditing, + onPopoverStateChange = null, + columns = [], + row, + currentTableData = [], + expandRow = false, +}) => { + const { dispatch } = React.useContext(AuthContext); + const { + dispatch: globalDispatch, + state: {}, + } = React.useContext(GlobalContext); + + const [listResult, setResult] = React.useState(null); + + const showWithLimit = (column) => { + if (expandRow) { + if (["string", "number"].includes(typeof listResult)) { + return ( + + {listResult} + + ); + } + + if (typeof listResult === "object" && Array.isArray(listResult)) { + return ( + <> + {listResult.map((item, itemKey) => { + return ( + + {item} + + ); + })} + + ); + } + } else { + if (["string", "number"].includes(typeof listResult)) { + return ( + + {listResult} + + ); + } + if (typeof listResult === "object" && Array.isArray(listResult)) { + const lengthToHide = + listResult.length > column.limit + ? `+${listResult.length - column?.limit}` + : null; + const itemsToShow = listResult + .map((item, index) => { + if (index + 1 <= column.limit) { + return item; + } + }) + .filter(Boolean); + + if (lengthToHide) itemsToShow.push(lengthToHide); + + return ( + <> + {itemsToShow.map((item, itemKey) => { + return ( + + {item} + + ); + })} + + ); + } + } + }; + + const getColumnListData = async (value, column) => { + // TO DO the processList function + const result = await processList(value, column, globalDispatch, dispatch); + if (["string", "number"].includes(typeof result)) { + setResult(result); + } + + if (typeof result === "object" && Array.isArray(result)) { + setResult(() => [...result]); + } + }; + + React.useEffect(() => { + if (column?.list && !listResult) { + getColumnListData(row[column?.accessor], column); + } + }, [column?.accessor]); + + return ( +
+ {column?.accessor?.indexOf("image") > -1 || + (column?.accessor?.indexOf("photo") > -1 && column?.selected_column) ? ( + + } + openOnClick={false} + zIndex={999999999999999} + onPopoverStateChange={onPopoverStateChange} + place="left-end" + tooltipClasses={`whitespace-nowrap h-fit min-h-[1rem] max-h-fit w-[18.75rem] !rounded-lg border border-[#a8a8a8] !bg-white p-2 text-sm text-[#525252] shadow-md`} + > + + + + + + ) : (column?.accessor?.indexOf("pdf") > -1 || + column?.accessor?.indexOf("doc") > -1 || + column?.accessor?.indexOf("file") > -1 || + column?.accessor?.indexOf("video") > -1) && + column?.selected_column ? ( + + {" "} + View + + ) : column?.join && column?.selected_column ? ( + <> + {row[column?.join] && row[column?.join][column?.accessor] + ? row[column?.join][column?.accessor] + : null} + + ) : column?.mappingExist && + ["status", "role", "verify", "receipt_status"].includes( + column?.accessor + ) && + !["admin"].includes(tableRole) && + column?.selected_column ? ( + + {mappingValues[ + column?.mappings[row[column?.accessor]]?.toLowerCase() + ] ?? column?.mappings[row[column?.accessor]]} + + ) : column?.mappingExist && + allowEditing && + ["admin"].includes(tableRole) && + column?.selected_column ? ( + + ) : column?.mappingExist && + !allowEditing && + ["admin"].includes(tableRole) && + column?.selected_column ? ( + + {mappingValues[ + column?.mappings[row[column?.accessor]]?.toLowerCase() + ] ?? column?.mappings[row[column?.accessor]]} + + ) : !column?.mappingExist && + column?.accessor !== "id" && + column?.accessor !== "create_at" && + column?.accessor !== "update_at" && + column?.accessor !== "user_id" && + column?.accessor !== "" && + allowEditing && + column?.selected_column ? ( + + // handleTableCellChange( + // row[actionId], + // e.target.value, + // i, + // column?.accessor + // ) + // } + /> + ) : column?.truncate && column?.selected_column ? ( + <>{truncate(row[column?.accessor], 50)} + ) : column?.replace && column?.selected_column ? ( + <>{truncate(row[column?.accessor], 30)} + ) : column?.list && column?.selected_column ? ( + <> + {listResult ? ( +
+ {showWithLimit(column)} +
+ ) : ( + + )} + + ) : column?.isCurrency && column?.selected_column ? ( + <> + {column?.currency} + {row[column?.accessor]} + + ) : ["notes"].includes(column?.accessor) && column?.selected_column ? ( + + ) : column?.accessor !== "" && column?.selected_column ? ( + <> + {typeof row[column?.accessor] === "object" + ? null + : row[column?.accessor]} + + ) : null} +
+ ); +}; + +export default MkdListTableRow; diff --git a/src/components/MkdListTable/MkdListTableRowButtons.jsx b/src/components/MkdListTable/MkdListTableRowButtons.jsx new file mode 100644 index 0000000..5e6add0 --- /dev/null +++ b/src/components/MkdListTable/MkdListTableRowButtons.jsx @@ -0,0 +1,80 @@ +import React from "react"; +import { AddButton } from "Components/AddButton"; +import { processBind } from "./MkdListTableBindOperations"; + +const MkdListTableRowDropdown = ({ + row, + columns, + actions, + actionId = "id", + setDeleteId = null, +}) => { + return ( + <> +
+ {Object.keys(actions) + .filter( + (key) => + actions[key]?.locations && + actions[key]?.locations?.includes("buttons") + ) + .map((key, keyIndex) => { + if (actions[key]?.bind) { + switch (actions[key]?.bind?.action) { + case "hide": + if (!processBind(actions[key], row)) { + return ( + { + if (["delete"].includes(key)) { + if (setDeleteId) { + setDeleteId(row[actionId]); + } + } else if (actions[key]?.action) { + actions[key]?.action([row[actionId]]); + } + }} + className={`!h-[2rem] !w-[2.0713rem] !border-soft-200 !bg-white`} + > + {actions[key]?.icon + ? actions[key]?.icon + : actions[key]?.children ?? key} + + ); + } + } + } + if (!actions[key]?.bind) { + return ( + { + if (["delete"].includes(key) && !actions[key]?.action) { + if (setDeleteId) { + setDeleteId(row[actionId]); + } + } else if (actions[key]?.action) { + actions[key]?.action([row[actionId]]); + } + // if (actions[key]?.action) { + // actions[key]?.action([row[actionId]]); + // } + }} + className={`!h-[2rem] !w-[2.0713rem] !border-soft-200 !bg-white`} + > + {actions[key]?.icon + ? actions[key]?.icon + : actions[key]?.children ?? key} + + ); + } + })} +
+ + ); +}; + +export default MkdListTableRowDropdown; diff --git a/src/components/MkdListTable/MkdListTableRowDropdown.jsx b/src/components/MkdListTable/MkdListTableRowDropdown.jsx new file mode 100644 index 0000000..0fe5c60 --- /dev/null +++ b/src/components/MkdListTable/MkdListTableRowDropdown.jsx @@ -0,0 +1,119 @@ +import React from "react"; +import { AiFillEye } from "react-icons/ai"; +import { MkdPopover } from "Components/MkdPopover"; +import { DropdownOption } from "Components/DropdownOptions"; +import { KebabIcon, TrashIcon, EditIcon2, UpdateIcon } from "Assets/svgs"; +import { optionTypes } from "Utils/utils"; +import RenderDropdownActions from "./RenderDropdownActions"; +import RenderActions from "./RenderActions"; + +const MkdListTableRowDropdown = ({ + row, + columns, + actions, + actionId = "id", + setDeleteId, + onPopoverStateChange = null, +}) => { + return ( + <> +
+ } + tooltipClasses="!rounded-[.5rem] !min-w-[11rem] !px-0 !right-[3.25rem] !border bg-white" + place={"left-end"} + onPopoverStateChange={onPopoverStateChange} + > + {actions?.edit?.show && ( + } + name={"Edit"} + onClick={() => { + if (actions?.edit?.action) { + actions?.edit?.action([row[actionId]]); + } + }} + /> + )} + + {actions?.view?.show && ( + } + name={"View"} + onClick={() => { + if (actions?.view?.action) { + actions?.view?.action([row[actionId]]); + } + }} + /> + )} + + {actions?.status?.show && ( + } + name={getStatusMap(statusRow, statusCol, row)} + onClick={() => { + if (actions?.status?.action) { + actions?.status?.action([row[actionId]]); + } + }} + /> + )} + + {actions?.delete?.show && ( + } + name={"Delete"} + onClick={() => { + if (!actions[key]?.action) { + if (setDeleteId) { + setDeleteId(row[actionId]); + } + } else if (actions[key]?.action) { + actions[key]?.action([row[actionId]]); + } + // setDeleteId(row[actionId]); + }} + /> + )} + + {Object.keys(actions) + .filter( + (key) => + actions[key]?.show && + actions[key]?.locations && + actions[key]?.locations?.includes("dropdown") + ) + .map((key, keyIndex) => { + if ( + actions[key]?.type && + [optionTypes.DROPDOWN].includes(actions[key]?.type) + ) { + return ( + + ); + } else if (!actions[key]?.type) { + return ( + + ); + } + })} + +
+ + ); +}; + +export default MkdListTableRowDropdown; diff --git a/src/components/MkdListTable/MkdListTableSelectRow.jsx b/src/components/MkdListTable/MkdListTableSelectRow.jsx new file mode 100644 index 0000000..a052fa3 --- /dev/null +++ b/src/components/MkdListTable/MkdListTableSelectRow.jsx @@ -0,0 +1,85 @@ +import React, { Fragment } from "react"; + +const MkdListTableSelectRow = ({ + loading, + columns = [], + actions, + currentTableData = [], + areAllRowsSelected, + handleSelectAll, + handleSelectRow, + actionId = "id", + selectedIds, +}) => { + return ( + + {!loading && currentTableData?.length && columns.length ? ( + <> + {[actions?.select?.show].includes(true) || + columns.find((item) => item?.accessor === "row") ? ( +
+
+ {[actions?.select?.show].includes(true) ? ( +
+ {actions?.select?.multiple ? ( + + ) : null} +
+ ) : null} + {columns.find((item) => item.accessor === "row") ? ( +
+ Row +
+ ) : null} +
+ + {currentTableData?.map((rowData, rowDataIndex) => { + return ( +
+ {[actions?.select?.show].includes(true) && ( +
+ handleSelectRow(rowData[actionId])} + /> +
+ )} + {columns.find((item) => item.accessor === "row") ? ( +
+ {rowDataIndex + 1} +
+ ) : null} +
+ ); + })} +
+ ) : null} + + ) : null} +
+ ); +}; + +export default MkdListTableSelectRow; diff --git a/src/components/MkdListTable/MkdListTableV2.jsx b/src/components/MkdListTable/MkdListTableV2.jsx new file mode 100644 index 0000000..1553720 --- /dev/null +++ b/src/components/MkdListTable/MkdListTableV2.jsx @@ -0,0 +1,809 @@ +import React, { memo, useMemo } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "Utils/MkdSDK"; +import { StringCaser } from "Utils/utils"; +import { AuthContext, tokenExpireError } from "Context/Auth"; +import { + GlobalContext, + customRequest, + getMany, + setLoading as setGlobalLoading, +} from "Context/Global"; +import { + MkdListTable, + OverlayTableActions, + TableActions, +} from "Components/MkdListTable"; +import { AddButton } from "Components/AddButton"; +import TreeSDK from "Utils/TreeSDK"; +import "./MkdListTable.css"; +import { ExCircleIcon } from "Assets/svgs"; + +import { MkdInput } from "Components/MkdInput"; + +let sdk = new MkdSDK(); +// const getSchemaStructure = (schema) => { +// return; +// }; +const getType = (type) => { + switch (type) { + case "varchar": + return "text"; + case "text": + return "textarea"; + case "mediumtext": + return "textarea"; + case "longtext": + return "textarea"; + case "tinyint": + return "number"; + case "int": + return "number"; + case "bigint": + return "number"; + case "float": + return "number"; + case "double": + return "number"; + case "image": + return "image"; + case "file": + return "file"; + case "date": + return "date"; + case "datetime": + return "datetime"; + default: + return "text"; + } +}; + +/** + * @params {"dropwdown" | "ontop" | "overlay"} actionPostion + * + */ +const MkdListTableV2 = ({ + externalData = [], + useExternalData = false, + defaultColumns = [], + columnModel = null, + // setColumns, + actions = { + view: { show: true, multiple: true, action: null }, + edit: { show: true, multiple: true, action: null }, + delete: { show: true, multiple: true, action: null }, + select: { show: true, multiple: true, action: null }, + action: { + show: false, + multiple: false, + action: null, + showChildren: true, + children: "+", + type: "", + className: "", + locations: [], + icon: null, + }, + add: { + show: true, + multiple: true, + action: null, + showChildren: true, + children: "+", + type: "", + className: "", + }, + export: { + show: true, + multiple: true, + action: null, + showText: false, + className: "", + }, + }, + actionPostion = ["dropdown"], // "dropwdown" | "ontop" | "overlay" | "button" + actionId = "id", + tableRole = "admin", + table = "user", + tableTitle = "", + tableSchema = [], + hasFilter = true, + schemaFields = [], + showPagination = true, + defaultFilter = [], + refreshRef = null, + allowEditing = false, + allowSortColumns = true, + topClasses = "", + join = [], + filterDisplays = [], +}) => { + const tdk = new TreeSDK(); + + const { dispatch } = React.useContext(AuthContext); + const { + dispatch: globalDispatch, + state: { columModel }, + } = React.useContext(GlobalContext); + + const [query, setQuery] = React.useState(""); + const [currentTableData, setCurrentTableData] = React.useState([]); + const [pageSize, setPageSize] = React.useState(1000); + const [pageCount, setPageCount] = React.useState(0); + const [dataTotal, setDataTotal] = React.useState(0); + const [currentPage, setPage] = React.useState(1); + const [canPreviousPage, setCanPreviousPage] = React.useState(false); + const [canNextPage, setCanNextPage] = React.useState(false); + const [showDeleteModal, setShowDeleteModal] = React.useState(false); + const [deleteLoading, setDeleteLoading] = React.useState(false); + const [selectedOptions, setSelectedOptions] = React.useState([]); + const [filterConditions, setFilterConditions] = React.useState([]); + const [selectedItems, setSelectedItems] = React.useState([]); + const [searchValue, setSearchValue] = React.useState(""); + const [isSearchDirty, setIsSearchDirty] = React.useState(false); + // const [optionValue, setOptionValue] = React.useState("eq"); + const [isLoading, setIsLoading] = React.useState(false); + const [loading, setLoading] = React.useState(false); + const [runFilter, setRunFilter] = React.useState(false); + const [searchField, setSearchField] = React.useState("name"); + + const [columnData, setColumnData] = React.useState(null); + const [columns, setColumns] = React.useState([]); + const [columnId, setColumnId] = React.useState(0); + const [popoverShown, setPopoverShow] = React.useState(false); + + const selectedOptionsMemo = useMemo(() => selectedOptions, [selectedOptions]); + + const schema = yup.object({}); + + const { + register, + handleSubmit, + setError, + reset, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + function onSort(columnIndex) { + console.log(columns[columnIndex]); + if (columns[columnIndex].isSorted) { + columns[columnIndex].isSortedDesc = !columns[columnIndex].isSortedDesc; + } else { + columns.map((i) => (i.isSorted = false)); + columns.map((i) => (i.isSortedDesc = false)); + columns[columnIndex].isSorted = true; + } + + (async function () { + await getData(currentPage, pageSize, { + filterConditions, + order: columns[columnIndex].accessor, + direction: columns[columnIndex].isSortedDesc ? "desc" : "asc", + }); + })(); + } + + function updatePageSize(limit) { + (async function () { + setPageSize(limit); + + if (isSearchDirty && !searchValue) { + await getData(currentPage, limit); + setIsSearchDirty(false); + } else if (isSearchDirty && searchValue) { + getSearchData({ limit, page: currentPage }); + } + })(); + } + + function setOptionValue(field, value, uid) { + const tempSelectedOptions = [...selectedOptions]; + const data = tempSelectedOptions.map((item) => { + if (item?.uid === uid) { + return { + ...item, + [field]: value, + }; + } + return item; + }); + setSelectedOptions((prev) => [...data]); + // console.log("field", field); + if (field === "value") { + // console.log("field", field); + setRunFilter(true); + } + } + + function previousPage() { + (async function () { + if (isSearchDirty && !searchValue) { + // await getData(currentPage, pageSize, { filterConditions: [] }); + await getData( + currentPage - 1 > 0 ? currentPage - 1 : currentPage, + pageSize + ); + setIsSearchDirty(false); + } else if (isSearchDirty && searchValue) { + getSearchData({ + limit: pageSize, + page: currentPage - 1 > 0 ? currentPage - 1 : currentPage, + }); + } + })(); + } + + function updateCurrentPage(page) { + (async function () { + setPage(page); + if (isSearchDirty && !searchValue) { + await getData(page, pageSize); + setIsSearchDirty(false); + } else if (isSearchDirty && searchValue) { + getSearchData({ limit: pageSize, page }); + } + })(); + } + + function nextPage() { + (async function () { + if (isSearchDirty && !searchValue) { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : currentPage, + pageSize + ); + setIsSearchDirty(false); + } else if (isSearchDirty && searchValue) { + getSearchData({ + limit: pageSize, + page: currentPage + 1 <= pageCount ? currentPage + 1 : currentPage, + }); + } + })(); + } + + const addFilterCondition = (option, selectedValue, inputValue) => { + const input = + selectedValue === "eq" && isNaN(inputValue) + ? `${inputValue}` + : inputValue; + const condition = `${option},${selectedValue},${input}`.toLowerCase(); + setFilterConditions((prevConditions) => { + const newConditions = prevConditions.filter( + (condition) => !condition.includes(option) + ); + return [...newConditions, condition]; + }); + setSearchValue(inputValue); + }; + // options.size = payload.limit; + // options.order = payload.sortId; + // options.direction = payload.direction; + // options.page = payload.page; + // options.join = payload.join; + async function getData(pageNum, limitNum, currentTableData) { + // console.log("currentTableData >>", currentTableData); + try { + setLoading(true); + const result = await tdk.getPaginate(table, { + size: limitNum, + page: pageNum, + ...{ + ...(join && join.length + ? { + join, + } + : null), + }, + ...{ + ...(currentTableData?.order + ? { + order: currentTableData?.order, + direction: currentTableData?.direction, + } + : null), + }, + ...{ + ...(currentTableData?.filterConditions && + currentTableData?.filterConditions.length + ? { + filter: [ + ...currentTableData?.filterConditions, + ...(defaultFilter.length ? defaultFilter : []), + ], + } + : defaultFilter.length + ? { filter: [...defaultFilter] } + : null), + }, + }); + // sdk.setTable(table); + // const result = await sdk.callRestAPI( + // { + // payload: { + // ...currentTableData, + // ...{ + // ...(filterConditions.length + // ? { + // filter: [ + // ...(defaultFilter.length && defaultFilter), + // ...filterConditions, + // ], + // } + // : defaultFilter.length + // ? { filter: [...defaultFilter] } + // : null), + // }, + // }, + // page: pageNum, + // limit: limitNum, + // }, + // "PAGINATE" + // ); + // if (!result) { + // setLoading(false); + // } + setSelectedItems(() => []); + const { list, total, limit, num_pages, page } = result; + + setCurrentTableData(list); + console.log("v2 component fetch result"); + console.log(result); + console.log("list"); + console.log(list); + setPageSize(limit); + setPageCount(num_pages); + setPage(page); + setDataTotal(total); + setCanPreviousPage(page > 1); + setCanNextPage(page + 1 <= num_pages); + setLoading(false); + if (selectedItems?.length) { + setSelectedItems(() => []); + } + } catch (error) { + setLoading(false); + console.log("ERROR", error); + tokenExpireError(dispatch, error.message); + } + } + + const deleteItem = async (id) => { + async function deleteId(id) { + try { + setDeleteLoading(true); + sdk.setTable(table); + const result = await sdk.callRestAPI({ id }, "DELETE"); + if (!result?.error) { + setCurrentTableData((list) => + list.filter((x) => Number(x.id) !== Number(id)) + ); + setDeleteLoading(false); + setShowDeleteModal(false); + } + } catch (err) { + setDeleteLoading(false); + setShowDeleteModal(false); + tokenExpireError(dispatch, err?.message); + throw new Error(err); + } + } + + if (typeof id === "object") { + id.forEach(async (idToDelete) => { + await deleteId(idToDelete); + }); + } else if (typeof id === "number") { + await deleteId(id); + } + }; + + const exportTable = async (id) => { + try { + sdk.setTable(table); + const result = await sdk.exportCSV(); + } catch (err) { + throw new Error(err); + } + }; + + const handleAlphaSearchInput = async (e) => { + if ([e?.code?.toLowerCase(), e?.key?.toLowerCase()].includes("enter")) { + console.log("searchValue >>", searchValue); + if (isSearchDirty && !searchValue) { + await getData(currentPage, pageSize, { filterConditions: [] }); + setIsSearchDirty(false); + } else if (isSearchDirty && searchValue) { + getSearchData(); + } + } else { + setSearchValue(e?.target?.value); + if (!isSearchDirty) { + setIsSearchDirty(true); + } + } + }; + + const getSearchData = async (query = { limit: pageSize, page: 1 }) => { + try { + const apiEndpoint = `/v3/api/custom/qualitysign/generic/search/${table}?limit=${query?.limit}&page=${query?.page}`; + setLoading(true); + const result = await customRequest(globalDispatch, dispatch, { + endpoint: apiEndpoint, + method: "POST", + payload: { + search: searchValue, + columns: columns, + }, + }); + if (!result?.error) { + setSelectedItems(() => []); + const { data, total, limit, num_pages, page } = result; + + setCurrentTableData(() => data); + console.log("v2 component fetch search result"); + console.log(result); + console.log("list"); + console.log(data); + setPageSize(Number(limit)); + setPageCount(num_pages ?? pageCount); + setPage(Number(page)); + setDataTotal(Number(total)); + setCanPreviousPage(Number(page) > 1); + setCanNextPage( + Number(page) + 1 <= num_pages ? Number(num_pages) : pageCount + ); + setLoading(false); + if (selectedItems?.length) { + setSelectedItems(() => []); + } + } + setLoading(false); + } catch (error) { + setLoading(false); + } + }; + + const resetForm = async () => { + reset(); + await getData(currentPage, pageSize); + }; + + const onSubmit = (e) => { + let filters = []; + // find duplicate fields + const uniqueSet = new Set( + selectedOptionsMemo.map((item) => item?.accessor) + ); + if (uniqueSet?.size) { + uniqueSet.forEach((uniqueSetItem) => { + const filterSet = selectedOptionsMemo.filter( + (item) => item.accessor === uniqueSetItem + ); + console.log("filterSet >>", filterSet); + if (filterSet?.length > 0 && filterSet?.length > 1) { + const valueSet = filterSet + .map((item) => { + if (item?.value) { + return item; + } + }) + .filter(Boolean); + + if (valueSet.length > 1) { + // const value = `${uniqueSetItem},in,${valueSet + // .map((item) => item.value) + // .join(",")}`; + // filters.push(value); + valueSet.forEach((valueSetItem) => { + switch (valueSetItem?.operator) { + case "cs": + case "eq": + filters.push( + `qualitysign_${table}.${valueSetItem?.accessor},o${valueSetItem?.operator},${valueSetItem?.value}` + ); + break; + default: + filters.push( + `qualitysign_${table}.${valueSetItem?.accessor},${valueSetItem?.operator},${valueSetItem?.value}` + ); + } + }); + } else if (valueSet.length === 1) { + filters.push( + `qualitysign_${table}.${valueSet[0]?.accessor},${valueSet[0]?.operator},${valueSet[0]?.value}` + ); + } + } else if (filterSet?.length === 1) { + if (filterSet[0]?.value) { + filters.push( + `qualitysign_${table}.${filterSet[0]?.accessor},${filterSet[0]?.operator},${filterSet[0]?.value}` + ); + } + } + }); + } + // return console.log("filters >>", filters); + if (filters?.length) { + getData(currentPage, pageSize, { filterConditions: filters }); + } else { + getData(currentPage, pageSize, { filterConditions: [] }); + } + + // getData(currentPage, pageSize, filter); + }; + + async function updateTableData(id, key, updatedData) { + try { + // setLoading(true); + sdk.setTable(table); + const result = await sdk.callRestAPI( + { + id, + [key]: updatedData, + }, + "PUT" + ); + // if (result) { + // setLoading(false); + // } + + console.log("update user data"); + console.log(result); + } catch (error) { + // setLoading(false); + console.log("ERROR", error); + tokenExpireError(dispatch, error.message); + } + } + + async function handleTableCellChange(id, newValue, index, newValueKey) { + console.log(newValue); + console.log(index); + console.log(newValueKey); + let runApiCall; + newValue = isNaN(Number.parseInt(newValue)) + ? newValue + : Number.parseInt(newValue); + try { + clearTimeout(runApiCall); + runApiCall = setTimeout(async () => { + await updateTableData(id, newValueKey, newValue); + }, 200); + setCurrentTableData((prevData) => { + const updatedData = prevData.map((item, i) => { + if (i === index) { + return { + ...item, + [newValueKey]: newValue, + }; + } + return item; + }); + return updatedData; + }); + } catch (error) { + console.error(error); + } + } + const populateColums = (result) => { + setColumnId(result?.data[0]?.id); + setColumnData(result?.data[0]); + const data = + result?.data[0].columns && JSON.parse(result?.data[0].columns) + ? JSON.parse(result?.data[0].columns) + : []; + + console.log("data >>", data); + + if (data.length) { + setColumns(() => [...data]); + } else { + setColumns(() => [...defaultColumns]); + } + }; + + const getColumns = async () => { + setGlobalLoading(globalDispatch, true, "columModel"); + const result = await getMany(globalDispatch, dispatch, "column", [ + ...(columnModel + ? [`model,eq,'${columnModel}'`] + : [`model,eq,'${table}'`]), + `user_id,eq,0`, + ]); + + // console.log("result >>", result); + if (!result?.error && result?.data?.length) { + populateColums(result); + } else { + const result = await getMany(globalDispatch, dispatch, "column", [ + ...(columnModel + ? [`model,eq,'${columnModel}'`] + : [`model,eq,'${table}'`]), + `user_id,eq,0`, + ]); + if (!result?.error && result?.data?.length) { + populateColums(result); + } + } + setGlobalLoading(globalDispatch, false, "columModel"); + }; + + React.useEffect(() => { + if (useExternalData) { + setColumns(() => defaultColumns); + } else { + getColumns(); + } + }, [useExternalData]); + + // Update External Selected Items + React.useEffect(() => { + if (actions?.select?.action) { + actions.select.action(selectedItems); + } + }, [selectedItems?.length]); + + React.useEffect(() => { + const searchableCol = columns.find((col) => col?.searchable); + if (searchableCol) { + setSearchField(searchableCol?.accessor); + } + }, []); + + React.useEffect(() => { + if (useExternalData) { + setCurrentTableData(() => externalData); + } else { + getData(currentPage, pageSize, { filterConditions: [] }); + } + }, [useExternalData]); + + return ( +
+ {refreshRef && ( + + )} +
+

+ {tableTitle ? tableTitle : ""} +

+ +
+
+ {Object.keys(actions).map((key, keyIndex) => { + if ( + actions[key].show && + actions[key].hasOwnProperty("type") && + ["toggle"].includes(actions[key].type) + ) { + return ( + { + if (actions[key]?.action) { + actions[key]?.action(e?.target?.checked); + } + }} + label={actions[key]?.children ?? key} + value={actions[key]?.value} + /> + ); + } + })} + + {selectedItems?.length && actionPostion.includes("ontop") ? ( + + ) : null} + + {Object.keys(actions).map((key, keyIndex) => { + if ( + actions[key].show && + actions[key].hasOwnProperty("type") && + ["static"].includes(actions[key].type) + ) { + return ( + { + if (actions[key]?.action) { + actions[key]?.action(); + } + }} + title={actions[key]?.title ?? key} + // showChildren={actions?.add?.showChildren} + showPlus={false} + className={`!h-[2.5rem] ${actions[key]?.className}`} + loading={actions[key]?.loading ?? false} + disabled={actions[key]?.disabled ?? false} + icon={actions[key]?.icon ?? null} + > + {key === "delete" ? : null} + {actions[key].children ? ( + actions[key].children + ) : ( + <> + {StringCaser(key === "delete" ? "Remove" : key, { + casetype: "capitalize", + separator: " ", + })} + + )} + + ); + } + })} + + {actions?.add?.show && ( + { + if (actions?.add?.action) { + actions?.add?.action(); + } + }} + showChildren={actions?.add?.showChildren} + className={`!h-[2.5rem] ${actions?.add?.className}`} + > + {actions?.add?.children} + + )} +
+
+
+
+ +
+ {selectedItems?.length && actionPostion.includes("overlay") ? ( + + ) : null} +
+ ); +}; + +export default memo(MkdListTableV2); diff --git a/src/components/MkdListTable/OverlayTableActions.jsx b/src/components/MkdListTable/OverlayTableActions.jsx new file mode 100644 index 0000000..bbd83fc --- /dev/null +++ b/src/components/MkdListTable/OverlayTableActions.jsx @@ -0,0 +1,184 @@ +import React from "react"; +import { StringCaser, optionTypes } from "Utils/utils"; +import { AddButton } from "Components/AddButton"; +import { ChevronRightIcon, ExCircleIcon } from "Assets/svgs"; +import { MkdPopover } from "Components/MkdPopover"; +import { DropdownOption } from "Components/DropdownOptions"; + +const OverlayTableActions = ({ actions, selectedItems }) => { + return ( +
+
+ Selected: {selectedItems.length} +
+ {Object.keys(actions).filter( + (key) => + actions[key]?.show && + actions[key]?.locations && + actions[key]?.locations?.includes("overlay") + )?.length ? ( + <> + {Object.keys(actions) + .filter( + (key) => + actions[key]?.show && + actions[key]?.locations && + actions[key]?.locations?.includes("overlay") + ) + .map((key, keyIndex) => { + if ( + actions[key]?.type && + [optionTypes.DROPDOWN].includes(actions[key]?.type) + ) { + return ( + + ); + } else if (!actions[key]?.type) { + return ( + + ); + } + }) + .filter(Boolean)} + + ) : null} +
+ ); +}; + +export default OverlayTableActions; + +const RenderButtonDropdownActions = ({ action, actionKey, selectedItems }) => { + return ( + + + {action?.icon} + {action?.children ?? actionKey} + + + + } + zIndex={999} + className={`w-full`} + tooltipClasses="!rounded-[.5rem] !text-white w-full !min-w-[11rem] !px-0 !right-[3.25rem] !border" + place={"top-start"} + backgroundColor="#18181B" + > + {action?.options && Object.keys(action?.options).length + ? Object.keys(action?.options).map((key, keyIndex) => { + return ( + + ); + }) + : null} + + ); +}; + +const RenderButtonActions = ({ action, selectedItems }) => { + return ( + { + if (action?.action) { + action?.action(selectedItems); + } + }} + /> + ); +}; + +const RenderButtons = ({ selectedItems, action, actionKey }) => { + if (selectedItems && selectedItems?.length === 1 && !action?.multiple) { + return ( + { + if (action?.action) { + console.log("actionKey >>", actionKey); + action.action(selectedItems); + } + }} + > + {actionKey === "delete" ? : null} + {action.children ? ( + action.children + ) : ( + <> + {StringCaser(actionKey === "delete" ? "Remove" : actionKey, { + casetype: "capitalize", + separator: " ", + })} + + )} + + ); + } + if (selectedItems && selectedItems?.length >= 1 && action?.multiple) { + return ( + { + if (action?.action) { + console.log("actionKey >>", actionKey); + action.action(selectedItems); + } + }} + > + {actionKey === "delete" ? : null} + {action.children ? ( + action.children + ) : ( + <> + {StringCaser(actionKey === "delete" ? "Remove" : actionKey, { + casetype: "capitalize", + separator: " ", + })} + + )} + + ); + } +}; diff --git a/src/components/MkdListTable/RenderActions.jsx b/src/components/MkdListTable/RenderActions.jsx new file mode 100644 index 0000000..7218660 --- /dev/null +++ b/src/components/MkdListTable/RenderActions.jsx @@ -0,0 +1,43 @@ +import React from "react"; +import { DropdownOption } from "Components/DropdownOptions"; +import { processBind } from "./MkdListTableBindOperations"; + +const RenderActions = ({ action, row, actionId, key }) => { + if (action?.bind) { + switch (action?.bind?.action) { + case "hide": + if (!processBind(action, row)) { + return ( + { + if (action?.action) { + action?.action([row[actionId]]); + } + }} + /> + ); + } + } + } + if (!action?.bind) { + return ( + { + if (action?.action) { + action?.action([row[actionId]]); + } + }} + /> + ); + } +}; + +export default RenderActions; diff --git a/src/components/MkdListTable/RenderDropdownActions.jsx b/src/components/MkdListTable/RenderDropdownActions.jsx new file mode 100644 index 0000000..bcc5ec2 --- /dev/null +++ b/src/components/MkdListTable/RenderDropdownActions.jsx @@ -0,0 +1,41 @@ +import React from "react"; +import { MkdPopover } from "Components/MkdPopover"; +import { ChevronRightIcon } from "Assets/svgs"; +import RenderActions from "./RenderActions"; + +const RenderDropdownActions = ({ action, actionKey, row, actionId }) => { + return ( + + + {action?.icon} + {action?.children ?? actionKey} + + + + } + className={`w-full`} + tooltipClasses="!rounded-[.5rem] w-full !min-w-[11rem] !px-0 !right-[3.25rem] !border bg-white" + place={"left-start"} + backgroundColor="#fff" + > + {action?.options && Object.keys(action?.options).length + ? Object.keys(action?.options).map((key, keyIndex) => { + return ( + + ); + }) + : null} + + ); +}; + +export default RenderDropdownActions; diff --git a/src/components/MkdListTable/TableActions.jsx b/src/components/MkdListTable/TableActions.jsx new file mode 100644 index 0000000..75f2039 --- /dev/null +++ b/src/components/MkdListTable/TableActions.jsx @@ -0,0 +1,92 @@ +import React from "react"; +import { StringCaser } from "Utils/utils"; +import { AddButton } from "Components/AddButton"; + +const TableActions = ({ actions, selectedItems }) => { + return ( +
+ {Object.keys(actions) + .map((key) => actions[key].show) + .includes(true) ? ( + <> + {Object.keys(actions) + .map((key) => { + if ( + actions[key].show && + !["static"].includes(actions[key].type) && + !["select", "add", "export"].includes(key) + ) { + if ( + selectedItems && + selectedItems?.length === 1 && + !actions[key]?.multiple + ) { + return ( + { + if (actions[key]?.action) { + actions[key].action(selectedItems); + } + }} + > + {StringCaser(key, { + casetype: "capitalize", + separator: " ", + })} + + ); + } + if ( + selectedItems && + selectedItems?.length >= 1 && + actions[key]?.multiple + ) { + return ( + { + if (actions[key]?.action) { + actions[key].action(selectedItems); + } + }} + > + {StringCaser(key, { + casetype: "capitalize", + separator: " ", + })} + + ); + } + } + }) + .filter(Boolean)} + + ) : null} +
+ ); +}; + +export default TableActions; diff --git a/src/components/MkdListTable/index.js b/src/components/MkdListTable/index.js new file mode 100644 index 0000000..fe25986 --- /dev/null +++ b/src/components/MkdListTable/index.js @@ -0,0 +1,8 @@ +export { default as MkdListTable } from "./MkdListTable"; +export { default as MkdListTableV2 } from "./MkdListTableV2"; +export { default as TableActions } from "./TableActions"; +export { default as OverlayTableActions } from "./OverlayTableActions"; +export { default as MkdListTableRow } from "./MkdListTableRow"; +export { default as MkdListTableHead } from "./MkdListTableHead"; +export { default as MkdListTableRowButtons } from "./MkdListTableRowButtons"; +export { default as MkdListTableRowDropdown } from "./MkdListTableRowDropdown"; diff --git a/src/components/MkdPopover/MkdPopover.css b/src/components/MkdPopover/MkdPopover.css new file mode 100644 index 0000000..bb5b713 --- /dev/null +++ b/src/components/MkdPopover/MkdPopover.css @@ -0,0 +1,10 @@ +/* PopoverOnClick.css */ + +/* Customize the appearance of the tooltip */ +/* .tooltip { + background-color: white !important; + color: #fff; + padding: 0.5rem; + border-radius: 0.25rem; + font-size: 0.875rem; +} */ diff --git a/src/components/MkdPopover/MkdPopover.jsx b/src/components/MkdPopover/MkdPopover.jsx new file mode 100644 index 0000000..b757e93 --- /dev/null +++ b/src/components/MkdPopover/MkdPopover.jsx @@ -0,0 +1,61 @@ +import React, { useId } from "react"; +import { Tooltip as ReactTooltip } from "react-tooltip"; +import "./MkdPopover.css"; + +const MkdPopover = ({ + display, + className, + children, + tooltipClasses, + place = "bottom", + openOnClick = true, + zIndex = 99999, + onPopoverStateChange, + backgroundColor = "#fff", + textColor = "#000", +}) => { + const tooltipId = useId(); + const handleTooltipShow = () => { + if (onPopoverStateChange) { + onPopoverStateChange(true); + } + }; + + const handleTooltipHide = () => { + if (onPopoverStateChange) { + onPopoverStateChange(false); + } + }; + + return ( + <> +
+ +
+ textColor} + > + {children} + + + ); +}; + +export default MkdPopover; diff --git a/src/components/MkdPopover/MkdPopover.module.css b/src/components/MkdPopover/MkdPopover.module.css new file mode 100644 index 0000000..b3f1dec --- /dev/null +++ b/src/components/MkdPopover/MkdPopover.module.css @@ -0,0 +1,47 @@ +.button { + position: relative; + border: none; + color: #ffffff; + text-align: center; + -webkit-transition-duration: 0.4s; /* Safari */ + transition-duration: 0.4s; + text-decoration: none; + overflow: hidden; + cursor: pointer; +} +.button:after { + content: ""; + background: #4f46e5; + display: block; + position: absolute; + padding-top: 300%; + padding-left: 350%; + margin-left: -20px !important; + margin-top: -120%; + opacity: 0; + transition: all 0.8s; +} + +.button:active:after { + padding: 0; + margin: 0; + opacity: 1; + transition: 0s; +} +.tip { + position: absolute; + top: anchor(bottom); + left: anchor(50%); +} + +/* PopoverOnClick.css */ + +/* Customize the appearance of the tooltip */ +.tooltip { + background-color: #333; + color: #fff; + padding: 8px; + border-radius: 4px; + font-size: 14px; + /* Add any other styles you need */ +} diff --git a/src/components/MkdPopover/index.js b/src/components/MkdPopover/index.js new file mode 100644 index 0000000..5a6b5e1 --- /dev/null +++ b/src/components/MkdPopover/index.js @@ -0,0 +1,3 @@ +import { lazy } from "react"; + +export const MkdPopover = lazy(() => import("./MkdPopover")); diff --git a/src/components/Skeleton/Skeleton.jsx b/src/components/Skeleton/Skeleton.jsx new file mode 100644 index 0000000..ca9461f --- /dev/null +++ b/src/components/Skeleton/Skeleton.jsx @@ -0,0 +1,41 @@ +import React from "react"; +import Skeleton from "react-loading-skeleton"; + +const SkeletonLoader = ({ + className = "", + count = 5, + counts = [2, 1, 3, 1, 1], + circle = false, +}) => { + return ( +
+ {/* */} + {Array.from({ length: count }).map((_, index) => ( + 1 + ? 25 + : index + 1 === count + ? 25 + : 80 + } + circle={circle} + // style={{ marginBottom: "0.6rem" }} + /> + ))} +
+ ); +}; + +export default SkeletonLoader; + +{ + /* + + + */ +} diff --git a/src/components/Skeleton/index.js b/src/components/Skeleton/index.js new file mode 100644 index 0000000..dc09e78 --- /dev/null +++ b/src/components/Skeleton/index.js @@ -0,0 +1,6 @@ + + import { lazy } from "react"; + + export const SkeletonLoader = lazy(()=> import("./Skeleton")) + + \ No newline at end of file diff --git a/src/components/SnackBar.jsx b/src/components/SnackBar.jsx index b9d12f9..3554969 100644 --- a/src/components/SnackBar.jsx +++ b/src/components/SnackBar.jsx @@ -1,39 +1,128 @@ import React from "react"; -import { GlobalContext } from "../globalContext"; +import { GlobalContext } from "Context/Global"; const SnackBar = () => { - const { state, dispatch } = React.useContext(GlobalContext); - const show = state.globalMessage.length > 0; + const { + state: { globalMessage, toastStatus }, + dispatch, + } = React.useContext(GlobalContext); + const show = globalMessage.length > 0; return show ? (