feat: call transcripts

This commit is contained in:
deepvasoya 2025-05-29 17:55:28 +05:30
parent 3073ef90b8
commit 0d5161d20d
14 changed files with 836 additions and 454 deletions

361
package-lock.json generated
View File

@ -16,6 +16,7 @@
"@mui/styles": "^5.11.7", "@mui/styles": "^5.11.7",
"@mui/system": "^5.11.7", "@mui/system": "^5.11.7",
"@mui/x-date-pickers": "^8.2.0", "@mui/x-date-pickers": "^8.2.0",
"@mui/x-date-pickers-pro": "^8.4.0",
"axios": "^1.8.4", "axios": "^1.8.4",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"firebase": "^11.6.0", "firebase": "^11.6.0",
@ -124,12 +125,9 @@
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.27.0", "version": "7.27.3",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.3.tgz",
"integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", "integrity": "sha512-7EYtGezsdiDMyY80+65EzwiGmcJqpmcZCojSXaRgdrBaGtWTgDZKq69cPIVped6MkIM78cTQ2GOiEYjwOlG4xw==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@ -857,6 +855,14 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
} }
}, },
"node_modules/@fingerprintjs/fingerprintjs": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs/-/fingerprintjs-3.4.2.tgz",
"integrity": "sha512-3Ncze6JsJpB7BpYhqIgvBpfvEX1jsEKrad5hQBpyRQxtoAp6hx3+R46zqfsuQG4D9egQZ+xftQ0u4LPFMB7Wmg==",
"dependencies": {
"tslib": "^2.4.1"
}
},
"node_modules/@firebase/analytics": { "node_modules/@firebase/analytics": {
"version": "0.10.12", "version": "0.10.12",
"resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.12.tgz", "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.12.tgz",
@ -2173,13 +2179,13 @@
} }
}, },
"node_modules/@mui/x-date-pickers": { "node_modules/@mui/x-date-pickers": {
"version": "8.2.0", "version": "8.4.0",
"resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-8.2.0.tgz", "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-8.4.0.tgz",
"integrity": "sha512-nkFzKkaDr4a9uto4pSOsNBMh+M2YQWiW9iYyBDOi5wOa983e2xMeb7zFjHGJ0xaycg1kfxNcbvJd7tm4Ub+RhA==", "integrity": "sha512-x7jI7JnKK25xL3yjD2Z1r86gAWtabKj9ogI2WDKd/v9WwE1VxmDD/NTiXprEZFo9psPOoqr+juPGDz5Cb2v7jw==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.27.0", "@babel/runtime": "^7.27.1",
"@mui/utils": "^7.0.2", "@mui/utils": "^7.0.2",
"@mui/x-internals": "8.2.0", "@mui/x-internals": "8.4.0",
"@types/react-transition-group": "^4.4.12", "@types/react-transition-group": "^4.4.12",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
@ -2237,12 +2243,74 @@
} }
} }
}, },
"node_modules/@mui/x-internals": { "node_modules/@mui/x-date-pickers-pro": {
"version": "8.2.0", "version": "8.4.0",
"resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.2.0.tgz", "resolved": "https://registry.npmjs.org/@mui/x-date-pickers-pro/-/x-date-pickers-pro-8.4.0.tgz",
"integrity": "sha512-qV4Qr+m4sAPBSuqu8/Ofi5m+nMMvIybGno6cp757bHSmwxkqrn5SKaGyFnH5kB58fOhYA9hG1UivFp7mO1dE4A==", "integrity": "sha512-/PTrkeYMu7Dm3W83iUmRb5J98RK6WAKjUksILLTgYfBdzv9CAhHXF+eG3LocD6Xqv5UJP+7m19lRH9vCsk/JMA==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.27.0", "@babel/runtime": "^7.27.1",
"@mui/utils": "^7.0.2",
"@mui/x-date-pickers": "8.4.0",
"@mui/x-internals": "8.4.0",
"@mui/x-license": "8.4.0",
"clsx": "^2.1.1",
"prop-types": "^15.8.1",
"react-transition-group": "^4.4.5"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1",
"@mui/material": "^5.15.14 || ^6.0.0 || ^7.0.0",
"@mui/system": "^5.15.14 || ^6.0.0 || ^7.0.0",
"date-fns": "^2.25.0 || ^3.2.0 || ^4.0.0",
"date-fns-jalali": "^2.13.0-0 || ^3.2.0-0 || ^4.0.0-0",
"dayjs": "^1.10.7",
"luxon": "^3.0.2",
"moment": "^2.29.4",
"moment-hijri": "^2.1.2 || ^3.0.0",
"moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
},
"date-fns": {
"optional": true
},
"date-fns-jalali": {
"optional": true
},
"dayjs": {
"optional": true
},
"luxon": {
"optional": true
},
"moment": {
"optional": true
},
"moment-hijri": {
"optional": true
},
"moment-jalaali": {
"optional": true
}
}
},
"node_modules/@mui/x-internals": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.4.0.tgz",
"integrity": "sha512-Z7FCahC4MLfTVzEwnKOB7P1fiR9DzFuMzHOPRNaMXc/rsS7unbtBKAG94yvsRzReCyjzZUVA7h37lnQ1DoPKJw==",
"dependencies": {
"@babel/runtime": "^7.27.1",
"@mui/utils": "^7.0.2" "@mui/utils": "^7.0.2"
}, },
"engines": { "engines": {
@ -2256,6 +2324,41 @@
"react": "^17.0.0 || ^18.0.0 || ^19.0.0" "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
} }
}, },
"node_modules/@mui/x-license": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/@mui/x-license/-/x-license-8.4.0.tgz",
"integrity": "sha512-kISlcCZWmg8r7FtYDdrHudx3t+WcvXCAaSF21zaJSSgedOoAP5InYuOxOVoSAUoE1eKU28+Ef9aLWCL1V4Zalw==",
"dependencies": {
"@babel/runtime": "^7.27.1",
"@mui/utils": "^7.0.2",
"@mui/x-internals": "8.4.0",
"@mui/x-telemetry": "8.4.0"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/@mui/x-telemetry": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/@mui/x-telemetry/-/x-telemetry-8.4.0.tgz",
"integrity": "sha512-nyCkfq8iB55dFhbeIrR+qVbSEZdTa1t6uOZWzz+md2pTaV6vf4s5Lp9LZikl+LrdL+LXb1ixzU+/TTS3YELXrw==",
"hasInstallScript": true,
"dependencies": {
"@babel/runtime": "^7.27.1",
"@fingerprintjs/fingerprintjs": "^3.4.2",
"@mui/utils": "^7.0.2",
"ci-info": "^4.2.0",
"conf": "^11.0.2",
"is-docker": "^3.0.0",
"node-machine-id": "^1.1.12"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@popperjs/core": { "node_modules/@popperjs/core": {
"version": "2.11.8", "version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
@ -2990,6 +3093,42 @@
"url": "https://github.com/sponsors/epoberezkin" "url": "https://github.com/sponsors/epoberezkin"
} }
}, },
"node_modules/ajv-formats": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"dependencies": {
"ajv": "^8.0.0"
},
"peerDependencies": {
"ajv": "^8.0.0"
},
"peerDependenciesMeta": {
"ajv": {
"optional": true
}
}
},
"node_modules/ajv-formats/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ajv-formats/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
},
"node_modules/ansi-regex": { "node_modules/ansi-regex": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
@ -3023,6 +3162,15 @@
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
}, },
"node_modules/atomically": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/atomically/-/atomically-2.0.3.tgz",
"integrity": "sha512-kU6FmrwZ3Lx7/7y3hPS5QnbJfaohcIul5fGqf7ok+4KklIEk9tJ0C2IQPdacSbVUWv6zVHXEBWoWd6NrVMT7Cw==",
"dependencies": {
"stubborn-fs": "^1.2.5",
"when-exit": "^2.1.1"
}
},
"node_modules/attr-accept": { "node_modules/attr-accept": {
"version": "2.2.5", "version": "2.2.5",
"resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz", "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz",
@ -3107,6 +3255,20 @@
"url": "https://github.com/chalk/chalk?sponsor=1" "url": "https://github.com/chalk/chalk?sponsor=1"
} }
}, },
"node_modules/ci-info": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz",
"integrity": "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/sibiraj-s"
}
],
"engines": {
"node": ">=8"
}
},
"node_modules/classnames": { "node_modules/classnames": {
"version": "2.5.1", "version": "2.5.1",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
@ -3166,6 +3328,47 @@
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true "dev": true
}, },
"node_modules/conf": {
"version": "11.0.2",
"resolved": "https://registry.npmjs.org/conf/-/conf-11.0.2.tgz",
"integrity": "sha512-jjyhlQ0ew/iwmtwsS2RaB6s8DBifcE2GYBEaw2SJDUY/slJJbNfY4GlDVzOs/ff8cM/Wua5CikqXgbFl5eu85A==",
"dependencies": {
"ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
"atomically": "^2.0.0",
"debounce-fn": "^5.1.2",
"dot-prop": "^7.2.0",
"env-paths": "^3.0.0",
"json-schema-typed": "^8.0.1",
"semver": "^7.3.8"
},
"engines": {
"node": ">=14.16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/conf/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/conf/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
},
"node_modules/convert-source-map": { "node_modules/convert-source-map": {
"version": "1.9.0", "version": "1.9.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
@ -3231,6 +3434,20 @@
"url": "https://github.com/sponsors/kossnocorp" "url": "https://github.com/sponsors/kossnocorp"
} }
}, },
"node_modules/debounce-fn": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-5.1.2.tgz",
"integrity": "sha512-Sr4SdOZ4vw6eQDvPYNxHogvrxmCIld/VenC5JbNrFwMiwd7lY/Z18ZFfo+EWNG4DD9nFlAujWAo/wGuOPHmy5A==",
"dependencies": {
"mimic-fn": "^4.0.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.0", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
@ -3278,6 +3495,20 @@
"csstype": "^3.0.2" "csstype": "^3.0.2"
} }
}, },
"node_modules/dot-prop": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-7.2.0.tgz",
"integrity": "sha512-Ol/IPXUARn9CSbkrdV4VJo7uCy1I3VuSiWCaFSg+8BdUOzF9n3jefIpcgAydvUZbTdEBZs2vEiTiS9m61ssiDA==",
"dependencies": {
"type-fest": "^2.11.2"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/dunder-proto": { "node_modules/dunder-proto": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@ -3296,6 +3527,17 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
}, },
"node_modules/env-paths": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz",
"integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/error-ex": { "node_modules/error-ex": {
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@ -3575,8 +3817,7 @@
"node_modules/fast-deep-equal": { "node_modules/fast-deep-equal": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
"dev": true
}, },
"node_modules/fast-json-stable-stringify": { "node_modules/fast-json-stable-stringify": {
"version": "2.1.0", "version": "2.1.0",
@ -3590,6 +3831,21 @@
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true "dev": true
}, },
"node_modules/fast-uri": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
]
},
"node_modules/faye-websocket": { "node_modules/faye-websocket": {
"version": "0.11.4", "version": "0.11.4",
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
@ -4012,6 +4268,20 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/is-docker": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
"integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
"bin": {
"is-docker": "cli.js"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-extglob": { "node_modules/is-extglob": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@ -4097,6 +4367,11 @@
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true "dev": true
}, },
"node_modules/json-schema-typed": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.1.tgz",
"integrity": "sha512-XQmWYj2Sm4kn4WeTYvmpKEbyPsL7nBsb647c7pMe6l02/yx2+Jfc4dT6UZkEXnIUb5LhD55r2HPsJ1milQ4rDg=="
},
"node_modules/json-stable-stringify-without-jsonify": { "node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
@ -4346,6 +4621,17 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/mimic-fn": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/minimatch": { "node_modules/minimatch": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@ -4387,6 +4673,11 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true "dev": true
}, },
"node_modules/node-machine-id": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.12.tgz",
"integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ=="
},
"node_modules/npm": { "node_modules/npm": {
"version": "11.3.0", "version": "11.3.0",
"resolved": "https://registry.npmjs.org/npm/-/npm-11.3.0.tgz", "resolved": "https://registry.npmjs.org/npm/-/npm-11.3.0.tgz",
@ -7307,11 +7598,6 @@
"redux": "^5.0.0" "redux": "^5.0.0"
} }
}, },
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
"node_modules/remove-accents": { "node_modules/remove-accents": {
"version": "0.5.0", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz",
@ -7325,6 +7611,14 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/resolve": { "node_modules/resolve": {
"version": "1.22.10", "version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
@ -7418,6 +7712,17 @@
"loose-envify": "^1.1.0" "loose-envify": "^1.1.0"
} }
}, },
"node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/shebang-command": { "node_modules/shebang-command": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -7492,6 +7797,11 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/stubborn-fs": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/stubborn-fs/-/stubborn-fs-1.2.5.tgz",
"integrity": "sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g=="
},
"node_modules/stylis": { "node_modules/stylis": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
@ -7709,6 +8019,11 @@
"node": ">=0.8.0" "node": ">=0.8.0"
} }
}, },
"node_modules/when-exit": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/when-exit/-/when-exit-2.1.4.tgz",
"integrity": "sha512-4rnvd3A1t16PWzrBUcSDZqcAmsUIy4minDXT/CZ8F2mVDgd65i4Aalimgz1aQkRGU0iH5eT5+6Rx2TK8o443Pg=="
},
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@ -18,6 +18,7 @@
"@mui/styles": "^5.11.7", "@mui/styles": "^5.11.7",
"@mui/system": "^5.11.7", "@mui/system": "^5.11.7",
"@mui/x-date-pickers": "^8.2.0", "@mui/x-date-pickers": "^8.2.0",
"@mui/x-date-pickers-pro": "^8.4.0",
"axios": "^1.8.4", "axios": "^1.8.4",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"firebase": "^11.6.0", "firebase": "^11.6.0",

View File

@ -31,6 +31,9 @@ import { useNavigate } from "react-router-dom";
import { useStyles } from "./styles/tableStyles"; import { useStyles } from "./styles/tableStyles";
import ProtectedComponent from "../components/ProtectedComponent"; import ProtectedComponent from "../components/ProtectedComponent";
import { DesktopDatePicker, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns";
import { DateRangePicker } from "@mui/x-date-pickers-pro";
const Table = memo( const Table = memo(
forwardRef((props, ref) => { forwardRef((props, ref) => {
@ -52,6 +55,7 @@ const Table = memo(
getRowStyle = () => {}, getRowStyle = () => {},
searchText, searchText,
navigateTo, navigateTo,
showDateFilters = false,
} = props; } = props;
const [data, setData] = useState([]); const [data, setData] = useState([]);
const [formattedColumns, setFormattedColumns] = useState([]); const [formattedColumns, setFormattedColumns] = useState([]);
@ -62,6 +66,7 @@ const Table = memo(
const [columnFilters, setColumnFilters] = useState([]); const [columnFilters, setColumnFilters] = useState([]);
const [globalFilter, setGlobalFilter] = useState(""); const [globalFilter, setGlobalFilter] = useState("");
const [sorting, setSorting] = useState([]); const [sorting, setSorting] = useState([]);
const [dateRange, setDateRange] = useState([null, null]);
const tableRef = useRef(); const tableRef = useRef();
const [pagination, setPagination] = useState({ const [pagination, setPagination] = useState({
pageIndex: options?.pageIndex ?? 0, pageIndex: options?.pageIndex ?? 0,
@ -69,6 +74,14 @@ const Table = memo(
}); });
const navigate = useNavigate(); const navigate = useNavigate();
useEffect(()=>{
if(dateRange){
console.log(dateRange);
}
},[dateRange])
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
reFetchData() { reFetchData() {
setIsLoading(true); setIsLoading(true);
@ -149,12 +162,20 @@ const Table = memo(
(sort) => `orderBy=${sort.id}&order=${sort.desc ? "DESC" : "ASC"}&` (sort) => `orderBy=${sort.id}&order=${sort.desc ? "DESC" : "ASC"}&`
) )
.join(""); .join("");
let startDate = "";
let endDate = "";
if (dateRange) {
startDate = dateRange[0];
endDate = dateRange[1];
}
try { try {
const response = await getData({ const response = await getData({
pagination, pagination,
filterString, filterString,
globalFilter, globalFilter,
sortingString, sortingString,
startDate,
endDate,
}); });
setData(response.data); setData(response.data);
setRowCount(response.rowCount); setRowCount(response.rowCount);
@ -178,6 +199,7 @@ const Table = memo(
pagination.pageIndex, pagination.pageIndex,
pagination.pageSize, pagination.pageSize,
sorting, sorting,
dateRange,
]); ]);
const debouncedSearch = useMemo( const debouncedSearch = useMemo(
@ -229,6 +251,32 @@ const Table = memo(
), ),
}} }}
/> />
{showDateFilters && (
<LocalizationProvider
className={classes.searchContainer}
dateAdapter={AdapterDateFns}
>
<DateRangePicker
className={classes.searchDatePicker}
renderInput={(props) => (
<TextField {...props} variant="outlined" />
)}
slotProps={{
field: {
clearable: true,
}
}}
value={dateRange}
onChange={(newValue) => {
setDateRange(newValue);
// column.setFilterValue(newValue);
}}
inputFormat="MMM d, yyyy"
format="MMM d, yyyy"
/>
</LocalizationProvider>
)}
{!hideShowPerPage && ( {!hideShowPerPage && (
<Box className={classes.pageSizeDropdown}> <Box className={classes.pageSizeDropdown}>
<Typography className={classes.dropDownLabel}>Show:</Typography> <Typography className={classes.dropDownLabel}>Show:</Typography>
@ -287,11 +335,11 @@ const Table = memo(
padding: "16px 8px", padding: "16px 8px",
whiteSpace: "nowrap", whiteSpace: "nowrap",
justifyContent: "flex-start", justifyContent: "flex-start",
'& .MuiTableSortLabel-root': { "& .MuiTableSortLabel-root": {
width: '100%', width: "100%",
justifyContent: 'flex-start', justifyContent: "flex-start",
} },
} },
}} }}
enableRowNumbers={enableRowNumbers} enableRowNumbers={enableRowNumbers}
rowNumberMode={rowNumberMode} rowNumberMode={rowNumberMode}
@ -383,28 +431,30 @@ const Table = memo(
className: classes?.tableCheckbox, className: classes?.tableCheckbox,
}} }}
renderRowActionMenuItems={({ row, closeMenu }) => renderRowActionMenuItems={({ row, closeMenu }) =>
actions?.filter(action => !action.render)?.map((action, index) => actions
!(action?.renderAction?.(row) ?? true) ? null : ( ?.filter((action) => !action.render)
<MenuItem ?.map((action, index) =>
key={index} !(action?.renderAction?.(row) ?? true) ? null : (
className={classes.menuItem} <MenuItem
onClick={(event) => { key={index}
event.stopPropagation(); className={classes.menuItem}
action.onClick && action.onClick(row); onClick={(event) => {
closeMenu(); event.stopPropagation();
}} action.onClick && action.onClick(row);
disabled={ closeMenu();
action?.isDisabledValue }}
? action?.isDisabledValue === disabled={
row?.original?.[action?.rowKey] action?.isDisabledValue
: false ? action?.isDisabledValue ===
} row?.original?.[action?.rowKey]
> : false
{action?.icon} {action?.text}{" "} }
{action.textFn && action.textFn(row)} >
</MenuItem> {action?.icon} {action?.text}{" "}
) {action.textFn && action.textFn(row)}
) ?? [] </MenuItem>
)
) ?? []
} }
renderTopToolbarCustomActions={({ table }) => { renderTopToolbarCustomActions={({ table }) => {
const handleActive = () => { const handleActive = () => {
@ -617,4 +667,4 @@ const CustomPagination = ({ table }) => {
); );
}; };
export default Table; export default Table;

View File

@ -150,6 +150,31 @@ export const useStyles = makeStyles((theme) => ({
opacity: 0.9, opacity: 0.9,
}, },
}, },
searchDatePicker: {
margin: theme.spacing(2.0),
backgroundColor: theme.palette.grey[0],
borderRadius: theme.spacing(1.8),
width: theme.spacing(32.0),
'& .MuiOutlinedInput-root': {
borderRadius: theme.spacing(1.8),
},
'&.MuiTextField-root': {
width: theme.spacing(40.0),
borderRadius: theme.spacing(1.8),
},
'& .MuiOutlinedInput-input::placeholder': {
fontStyle: 'normal',
fontSize: pxToRem(14),
color: theme.palette.grey[10],
opacity: 0.9,
},
'& .MuiPickersInputBase-root': {
borderRadius: theme.spacing(1.4),
},
'& .MuiPickersSectionList-root': {
padding: `12.5px !important`,
},
},
searchIconImg: { searchIconImg: {
width: theme.spacing(2.0), width: theme.spacing(2.0),
minWidth: theme.spacing(1.8), minWidth: theme.spacing(1.8),

View File

@ -52,7 +52,7 @@ axiosInstance.interceptors.request.use(
axiosInstance.interceptors.response.use( axiosInstance.interceptors.response.use(
function (response) { function (response) {
if (response?.data && response?.data?.error !== null) { if (response?.data && typeof response?.data === "object" && 'error' in response.data && response?.data?.error !== null) {
pushNotification(response?.data?.message, NOTIFICATION.ERROR); pushNotification(response?.data?.message, NOTIFICATION.ERROR);
return Promise.reject(response); return Promise.reject(response);
} }

View File

@ -108,3 +108,7 @@ div::-webkit-scrollbar-thumb:hover {
width: 4px; width: 4px;
background-color: transparent; background-color: transparent;
} }
div[style*="z-index: 100000"] {
visibility: hidden;
}

View File

@ -5,7 +5,7 @@ import { clinicsData, registeredClinicsData } from "../mock/clinics";
export const getClinics = (params) => { export const getClinics = (params) => {
let searchParams = new URLSearchParams(); let searchParams = new URLSearchParams();
searchParams.append("limit", params?.pagination?.pageSize ?? 10); searchParams.append("limit", params?.pagination?.pageSize ?? 10);
searchParams.append("page", params?.pagination.pageIndex+1 ?? 1); searchParams.append("page", params?.pagination.pageIndex + 1 ?? 1);
searchParams.append("filter_type", params?.type ?? CLINIC_TYPE.REGISTERED); searchParams.append("filter_type", params?.type ?? CLINIC_TYPE.REGISTERED);
searchParams.append("search", params?.globalFilter ?? ""); searchParams.append("search", params?.globalFilter ?? "");
@ -39,7 +39,7 @@ export const getClinicsById = (id) => {
}); });
}; };
export const generatePaymentSession = () =>{ export const generatePaymentSession = () => {
const url = `/stripe/create-payment-session`; const url = `/stripe/create-payment-session`;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axiosInstance axiosInstance
@ -47,7 +47,7 @@ export const generatePaymentSession = () =>{
.then((response) => resolve(response)) .then((response) => resolve(response))
.catch((err) => reject(err)); .catch((err) => reject(err));
}); });
} };
export const updateClinicStatus = (data) => { export const updateClinicStatus = (data) => {
const url = `/admin/clinic/status`; const url = `/admin/clinic/status`;
@ -102,7 +102,7 @@ export const createClinicOffer = (data) => {
export const getClinicOffer = (params) => { export const getClinicOffer = (params) => {
let searchParams = new URLSearchParams(); let searchParams = new URLSearchParams();
searchParams.append("limit", params?.pagination?.pageSize ?? 10); searchParams.append("limit", params?.pagination?.pageSize ?? 10);
searchParams.append("page", params?.pagination.pageIndex+1 ?? 1); searchParams.append("page", params?.pagination.pageIndex + 1 ?? 1);
searchParams.append("search", params?.globalFilter ?? ""); searchParams.append("search", params?.globalFilter ?? "");
const url = `/admin/clinic/offers?${searchParams.toString()}`; const url = `/admin/clinic/offers?${searchParams.toString()}`;
@ -134,11 +134,10 @@ export const deleteClinicOffer = (id) => {
}); });
}; };
export const getClinicDoctors = (params) => { export const getClinicDoctors = (params) => {
let searchParams = new URLSearchParams(); let searchParams = new URLSearchParams();
searchParams.append("limit", params?.pagination?.pageSize ?? 10); searchParams.append("limit", params?.pagination?.pageSize ?? 10);
searchParams.append("page", params?.pagination.pageIndex+1 ?? 1); searchParams.append("page", params?.pagination.pageIndex + 1 ?? 1);
searchParams.append("search", params?.globalFilter ?? ""); searchParams.append("search", params?.globalFilter ?? "");
const url = `/clinic-doctors?${searchParams.toString()}`; const url = `/clinic-doctors?${searchParams.toString()}`;
@ -148,7 +147,7 @@ export const getClinicDoctors = (params) => {
.then((response) => resolve(response)) .then((response) => resolve(response))
.catch((err) => reject(err)); .catch((err) => reject(err));
}); });
} };
export const createDoctor = (data) => { export const createDoctor = (data) => {
const url = `/clinic-doctors/`; const url = `/clinic-doctors/`;
@ -179,3 +178,57 @@ export const deleteDoctor = (id) => {
.catch((err) => reject(err)); .catch((err) => reject(err));
}); });
}; };
export const getCallTranscripts = (params) => {
console.log(params);
let searchParams = new URLSearchParams();
searchParams.append("limit", params?.pagination?.pageSize ?? 10);
searchParams.append("page", params?.pagination.pageIndex + 1 ?? 1);
searchParams.append("search", params?.globalFilter ?? "");
if(params?.startDate){
searchParams.append("startDate", params.startDate.toISOString());
}
if(params?.endDate){
searchParams.append("endDate", params.endDate.toISOString());
}
if (params?.sortingString) {
const sortingParams = new URLSearchParams(params.sortingString);
sortingParams.forEach((value, key) => {
searchParams.append(key, value);
});
}
const url = `/call-transcripts?${searchParams.toString()}`;
return new Promise((resolve, reject) => {
axiosInstance
.get(url)
.then((response) => resolve(response))
.catch((err) => reject(err));
});
};
export const downloadCallTranscript = (id) => {
const url = `/call-transcripts/${id}`;
return new Promise((resolve, reject) => {
axiosInstance
.get(url)
.then((response) => resolve(response))
.catch((err) => reject(err));
});
};
export const downloadBulkCallTranscripts = (data) => {
const url = `/call-transcripts/bulk-download`;
return new Promise((resolve, reject) => {
axiosInstance
.post(url, data, {
responseType: "blob",
transitional: {
forcedJSONParsing: false,
},
})
.then((response) => resolve(response))
.catch((err) => reject(err));
});
};

View File

@ -242,7 +242,7 @@ const FileEvaluate = ({
<Box className={classes.imageBox}> <Box className={classes.imageBox}>
<img <img
className={classes.image} className={classes.image}
src={file.file} src={file.fileURL}
alt="Uploaded File" alt="Uploaded File"
/> />
</Box> </Box>
@ -312,7 +312,7 @@ const FileEvaluate = ({
<Box className={classes.imageBox}> <Box className={classes.imageBox}>
<img <img
className={classes.image} className={classes.image}
src={file.fileURL} src={file.file}
alt="Uploaded File" alt="Uploaded File"
/> />
<Box className={classes?.onImageButton}> <Box className={classes?.onImageButton}>
@ -360,7 +360,7 @@ const FileEvaluate = ({
<Box className={classes.logoPreviewImageBox}> <Box className={classes.logoPreviewImageBox}>
<img <img
className={classes.image} className={classes.image}
src={file.fileURL} src={file.file}
alt={file.documentType} alt={file.documentType}
/> />
<Box className={classes?.onImageButton}> <Box className={classes?.onImageButton}>

View File

@ -0,0 +1,119 @@
import makeStyles from '@mui/styles/makeStyles';
import { pxToRem } from '../../theme/typography';
export const useStyles = makeStyles((theme) => ({
chipClass: {
height: 'fit-content',
minHeight: '30px',
padding: '2px',
alignItems: 'center',
},
statusColor: {
color: theme.palette.primary.main,
fontSize: pxToRem(10),
},
tabsBox: {
display: 'flex',
justifyContent: ' space-around',
// width: '55%',
marginTop: theme.spacing(0.5),
marginRight: theme.spacing(5.0),
alignItems: 'center',
},
secondaryButton: {
width: '200px',
height: '46px',
borderRadius: '8px',
justifyContent: 'space-evenly',
fontSize: pxToRem(16),
},
tableActionIcons: {
marginRight: theme.spacing(1.4),
width: '15px',
},
companyNameTableColumn: {
display: 'flex',
alignItems: 'center',
},
companyName: {
marginLeft: theme.spacing(1),
fontSize: pxToRem(14),
objectFit: 'contain',
width: '260px',
},
companyNameLink: {
textDecoration: 'none',
color: theme.palette.grey[10],
'&:hover': {
color: theme.palette.info.main,
textDecoration: 'underline',
},
},
companyWebsiteLabel: {
fontSize: pxToRem(12),
},
companyNameLogo: {
height: '40px',
width: '40px',
borderRadius: theme.shape.borderRadiusComponent,
objectFit: 'contain',
},
sendEmailStatus: {
fontSize: pxToRem(14),
color: theme.palette.primary.main,
},
sendEmailLastSentMailDate: {
fontSize: pxToRem(12),
},
addDiscountCodeLink: {
fontSize: pxToRem(12),
color: theme.palette.primary.main,
},
addDiscountCodeLabel: {
fontSize: pxToRem(14),
backgroundColor: theme.palette.common.white,
color: theme.palette.common.black,
},
customModel: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: '100%',
},
customModelBox: {
paddingLeft: theme.spacing(5),
paddingRight: theme.spacing(5),
textAlign: 'center',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
// height: '100%',
border: 'none',
},
newPlanTitleText: {
fontSize: pxToRem(28),
fontFamily: theme.fontFamily.bold,
},
newPlanSubTitleText: {
fontSize: pxToRem(18),
padding: theme.spacing(1),
},
addPlanSuccessIcon: {
padding: theme.spacing(2),
paddingTop: theme.spacing(1),
},
planAddedText: {
fontSize: pxToRem(12),
color: theme.palette.grey[54],
display: 'flex',
alignItems: 'center',
alignSelf: 'center',
},
verifyIcon: {
marginLeft: theme.spacing(0.3),
fontSize: pxToRem(12),
color: theme.palette.grey[54],
},
}));

View File

@ -1,400 +1,215 @@
import DownloadIcon from '@mui/icons-material/Download'; import DownloadIcon from "@mui/icons-material/Download";
import FilterListIcon from '@mui/icons-material/FilterList'; import { Box, IconButton, LinearProgress, TextField } from "@mui/material";
import { format } from "date-fns";
import React, { useEffect, useMemo, useRef, useState } from "react";
import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns";
import Table from "../../components/Table";
import { import {
Box, downloadBulkCallTranscripts,
Button, getCallTranscripts,
IconButton, } from "../../services/clinics.service";
Paper, import { useStyles } from "./clinicTranscriptsStyles";
Table, import PageHeader from "../../components/PageHeader";
TableBody, import CustomBreadcrumbs from "../../components/CustomBreadcrumbs";
TableCell, import { DesktopDatePicker, LocalizationProvider } from "@mui/x-date-pickers";
TableContainer,
TableHead,
TablePagination,
TableRow,
TableSortLabel,
Typography,
TextField,
} from '@mui/material';
import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { format } from 'date-fns';
import React, { useEffect, useState } from 'react';
// Sample data - replace with your actual data source
const sampleCalls = [
{
id: 1,
date: '2025-04-20',
time: '09:30',
callerNumber: '555-123-4567',
patientName: 'John Smith',
callDuration: Math.floor(Math.random() * 60),
},
{
id: 2,
date: '2025-04-21',
time: '10:15',
callerNumber: '555-234-5678',
patientName: 'Jane Doe',
callDuration: Math.floor(Math.random() * 60),
},
{
id: 3,
date: '2025-04-19',
time: '14:45',
callerNumber: '555-345-6789',
patientName: 'Robert Johnson',
callDuration: Math.floor(Math.random() * 60),
},
{
id: 4,
date: '2025-04-22',
time: '11:00',
callerNumber: '555-456-7890',
patientName: 'Emily Davis',
callDuration: Math.floor(Math.random() * 60),
},
{
id: 5,
date: '2025-04-20',
time: '16:30',
callerNumber: '555-567-8901',
patientName: 'Michael Brown',
callDuration: Math.floor(Math.random() * 60),
},
{
id: 6,
date: '2025-04-19',
time: '14:45',
callerNumber: '555-345-6789',
patientName: 'Robert Johnson',
callDuration: Math.floor(Math.random() * 60),
},
{
id: 7,
date: '2025-04-22',
time: '11:00',
callerNumber: '555-456-7890',
patientName: 'Emily Davis',
callDuration: Math.floor(Math.random() * 60),
},
{
id: 8,
date: '2025-04-20',
time: '16:30',
callerNumber: '555-567-8901',
patientName: 'Michael Brown',
callDuration: Math.floor(Math.random() * 60),
},
{
id: 9,
date: '2025-04-19',
time: '14:45',
callerNumber: '555-345-6789',
patientName: 'Robert Johnson',
callDuration: Math.floor(Math.random() * 60),
},
{
id: 10,
date: '2025-04-22',
time: '11:00',
callerNumber: '555-456-7890',
patientName: 'Emily Davis',
callDuration: Math.floor(Math.random() * 60),
},
{
id: 11,
date: '2025-04-20',
time: '16:30',
callerNumber: '555-567-8901',
patientName: 'Michael Brown',
callDuration: Math.floor(Math.random() * 60),
},
];
const CallListTable = () => { const CallListTable = () => {
const [calls, setCalls] = useState([]); const classes = useStyles();
const [orderBy, setOrderBy] = useState('date'); const ref = useRef(null);
const [order, setOrder] = useState('desc');
const [showFilters, setShowFilters] = useState(false);
const [startDate, setStartDate] = useState(null);
const [endDate, setEndDate] = useState(null);
// Pagination state const [loading, setLoading] = useState(false);
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(5);
// Initialize with sample data const [data, setData] = useState([]);
useEffect(() => {
setCalls(sampleCalls);
}, []);
// Handle sort request // get data
const handleRequestSort = (property) => { const getTranscrips = async (filters) => {
const isAsc = orderBy === property && order === 'asc'; try {
setOrder(isAsc ? 'desc' : 'asc'); const params = { ...filters };
setOrderBy(property); const resp = await getCallTranscripts(params);
}; setData(resp?.data?.data?.data);
return {
const formatDate = (dateString) => { data: resp?.data?.data?.data,
const date = new Date(dateString); rowCount: resp?.data?.data?.total || 0,
const day = date.getDate().toString().padStart(2, '0'); };
const month = date.toLocaleString('en-US', { month: 'short' }); } catch (error) {
const year = date.getFullYear(); console.log(error);
return `${day}-${month}-${year}`; return {
}; data: [],
rowCount: 0,
// Handle download transcript };
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const handleDownloadTranscript = (id) => {
// TODO: Implement actual download functionality here
};
// Apply filters
const applyFilters = () => {
let filteredCalls = [...sampleCalls];
if (startDate) {
const startDateStr = format(startDate, 'yyyy-MM-dd');
filteredCalls = filteredCalls.filter((call) => call.date >= startDateStr);
} }
};
if (endDate) { const handleBulkDownload = async () => {
const endDateStr = format(endDate, 'yyyy-MM-dd'); try {
filteredCalls = filteredCalls.filter((call) => call.date <= endDateStr); setLoading(true);
const keys = data.map((item) => item.id);
const downloadResponse = await downloadBulkCallTranscripts(keys);
// const blob = new Blob([downloadResponse?.data], { type: "application/zip" });
const url = window.URL.createObjectURL(downloadResponse?.data);
const a = document.createElement("a");
a.href = url;
a.download = "transcripts.zip";
document.body.appendChild(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
} catch (error) {
console.log(error);
} finally {
setLoading(false);
} }
setCalls(filteredCalls);
setPage(0); // Reset to first page after filtering
}; };
// Reset filters const columns = useMemo(() => [
const resetFilters = () => { {
setStartDate(null); size: 100,
setEndDate(null); header: "Sr. No.",
setCalls(sampleCalls); Cell: (props) => {
setPage(0); // Reset to first page after clearing filters const tableState = props?.table?.getState();
}; const serialNumber = (
props?.row?.index +
1 +
tableState?.pagination?.pageIndex * tableState?.pagination?.pageSize
)
?.toString()
?.padStart(1, "0");
return <span>{serialNumber}</span>;
},
enableSorting: false,
},
{
id: "call_duration",
size: 200,
accessorKey: "call_duration",
header: "Call Duration",
Cell: (props) => {
const totalSeconds = parseInt(props.row.original.call_duration);
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
return (
<span>
{minutes > 0 ? `${minutes} min ` : ""}
{seconds > 0 || minutes === 0 ? `${seconds} sec` : ""}
</span>
);
},
enableSorting: false,
enableColumnFilter: false,
},
{
id: "call_received_time",
size: 200,
accessorKey: "call_received_time",
header: "Call Received Time",
Cell: (props) => {
const date = new Date(props.row.original.call_received_time);
const formattedDate = format(date, "MMM d, yyyy h:mm a");
return <span>{formattedDate}</span>;
},
enableSorting: false,
enableColumnFilter: false,
},
{
id: "patient_number",
size: 200,
accessorKey: "patient_number",
header: "Patient Number",
Cell: (props) => {
return <span>{props.row.original.patient_number}</span>;
},
enableColumnFilter: false,
},
{
size: 20,
accessorKey: "download",
header: "",
enableColumnFilter: false,
enableSorting: false,
Cell: (props) => {
const { row } = props;
const handleDownload = async () => {
const a = document.createElement("a");
a.href = row.original.transcript_key_id;
a.download = "transcript.txt";
document.body.appendChild(a);
a.click();
a.remove();
};
return (
<IconButton onClick={handleDownload}>
<DownloadIcon />
</IconButton>
);
},
enableColumnFilter: false,
},
// {
// id: "patient_name",
// size: 150,
// accessorKey: "patient_name",
// header: "Patient Name",
// Cell: (props) => {
// return <span>{props.row.original.patient_name}</span>;
// },
// enableColumnFilter: false,
// },
]);
// Handle page change const breadcrumbs = [
const handleChangePage = (event, newPage) => { {
setPage(newPage); label: "Dashboard",
}; path: "/",
},
{
label: "Call Transcripts",
path: "/transcripts",
},
];
// Handle rows per page change
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
};
// Sort function
const sortedCalls = calls.sort((a, b) => {
if (orderBy === 'date') {
const dateComparison = a.date.localeCompare(b.date);
if (dateComparison !== 0)
return order === 'asc' ? dateComparison : -dateComparison;
// If dates are equal, sort by time
return order === 'asc'
? a.time.localeCompare(b.time)
: b.time.localeCompare(a.time);
}
if (orderBy === 'time') {
return order === 'asc'
? a.time.localeCompare(b.time)
: b.time.localeCompare(a.time);
}
return 0;
});
// Get current page data
const currentPageCalls = sortedCalls.slice(
page * rowsPerPage,
page * rowsPerPage + rowsPerPage
);
// Custom render function for DatePicker to avoid renderInput prop issues
const CustomDateField = ({ value, onChange, label }) => (
<TextField
label={label}
value={value ? format(value, 'yyyy-MM-dd') : ''}
onChange={(e) => {
try {
const dateStr = e.target.value;
const date = new Date(dateStr);
if (!isNaN(date.getTime())) {
onChange(date);
}
} catch (error) {
// Invalid date
}
}}
placeholder="YYYY-MM-DD"
size="small"
sx={{ minWidth: 200 }}
/>
);
return ( return (
<Box sx={{ width: '100%' }}> <Box>
<Paper sx={{ width: '100%', mb: 2 }}> <PageHeader
<Box pageTitle="Call Transcripts"
sx={{ addButtonIcon={<DownloadIcon />}
p: 2, addButtonTitle="Bulk Download"
display: 'flex', onAddButtonClick={handleBulkDownload}
justifyContent: 'space-between', />
alignItems: 'center', <CustomBreadcrumbs breadcrumbs={breadcrumbs} />
}} <Box className={classes.tableMainDiv}>
> <Box className={classes.table}>
<Typography variant="h6" component="div"> {loading && <LinearProgress />}
Call Transcripts <Table
</Typography> tableRef={ref}
<Box sx={{ display: 'flex', gap: 2 }}> options={{
<Button enableRowSelection: false,
variant="contained" showTopBar: true,
color="primary" showFilters: true,
startIcon={<DownloadIcon />}
onClick={() => {
/* TODO: Implement bulk download */
}}
sx={{ bgcolor: '#f5365c', '&:hover': { bgcolor: '#d40639' } }}
>
Bulk Download
</Button>
<Button
startIcon={<FilterListIcon />}
onClick={() => setShowFilters(!showFilters)}
color={showFilters ? 'secondary' : 'primary'}
sx={{ color: showFilters ? '#f5365c' : undefined }}
>
{showFilters ? 'Hide Filters' : 'Show Filters'}
</Button>
</Box>
</Box>
{showFilters && (
<Box
sx={{
p: 2,
display: 'flex',
gap: 2,
flexWrap: 'wrap',
alignItems: 'center',
}} }}
> topToolbarProps={{
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Box> }}
<CustomDateField renderTopToolbar={() => {
label="Start Date (YYYY-MM-DD)" return (
value={startDate} <Box>
onChange={setStartDate} <TextField
/> variant="outlined"
</Box> value={"123"}
onChange={(e) => setSearchText(e.target.value)}
<Box> placeholder="Search..."
<CustomDateField />
label="End Date (YYYY-MM-DD)" </Box>
value={endDate} );
onChange={setEndDate} }}
/> showDateFilters
</Box> columns={columns}
</LocalizationProvider> getData={getTranscrips}
searchText="Transcripts"
<Button />
variant="contained" </Box>
onClick={applyFilters} </Box>
sx={{ bgcolor: '#f5365c', '&:hover': { bgcolor: '#d40639' } }}
>
Apply Filters
</Button>
<Button
variant="outlined"
onClick={resetFilters}
sx={{
color: '#f5365c',
borderColor: '#f5365c',
'&:hover': { borderColor: '#d40639' },
}}
>
Reset
</Button>
</Box>
)}
<TableContainer>
<Table sx={{ minWidth: 750 }} aria-labelledby="callListTable">
<TableHead>
<TableRow>
<TableCell>
<TableSortLabel
active={orderBy === 'date'}
direction={orderBy === 'date' ? order : 'asc'}
onClick={() => handleRequestSort('date')}
>
Date
</TableSortLabel>
</TableCell>
<TableCell>
<TableSortLabel
active={orderBy === 'time'}
direction={orderBy === 'time' ? order : 'asc'}
onClick={() => handleRequestSort('time')}
>
Received Time
</TableSortLabel>
</TableCell>
<TableCell>Call Duration</TableCell>
<TableCell>Caller Number</TableCell>
<TableCell>Patient Name</TableCell>
<TableCell align="center">Action</TableCell>
</TableRow>
</TableHead>
<TableBody>
{currentPageCalls.map((call) => (
<TableRow key={call.id}>
<TableCell component="th" scope="row">
{formatDate(call.date)}
</TableCell>
<TableCell>{call.time}</TableCell>
<TableCell>{call.callDuration} Sec</TableCell>
<TableCell>{call.callerNumber}</TableCell>
<TableCell>{call.patientName}</TableCell>
<TableCell align="center">
<IconButton
color="primary"
onClick={() => handleDownloadTranscript(call.id)}
aria-label="download transcript"
sx={{ color: '#f5365c' }}
>
<DownloadIcon />
</IconButton>
</TableCell>
</TableRow>
))}
{currentPageCalls.length === 0 && (
<TableRow>
<TableCell colSpan={5} align="center">
No calls found
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
component="div"
count={sortedCalls.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</Paper>
</Box> </Box>
); );
}; };

View File

@ -15,7 +15,7 @@ const SuperAdminTotals = ({ isLoading, data }) => {
// navigate(path, { state: { tab } }); // navigate(path, { state: { tab } });
}; };
const { totalAccounts, registrationRequest, rejected, registered } = data; const { totalAccounts, registrationRequest, rejected, registered, paymentDue } = data;
return ( return (
<ProtectedComponent> <ProtectedComponent>
@ -51,7 +51,7 @@ const SuperAdminTotals = ({ isLoading, data }) => {
heading={`Payment Due`} heading={`Payment Due`}
isLoading={isLoading} isLoading={isLoading}
viewAllClick={() => viewAllClick(false)} viewAllClick={() => viewAllClick(false)}
value={rejected} value={paymentDue}
color={theme.palette.grey[57]} color={theme.palette.grey[57]}
/> />
</Grid> </Grid>

View File

@ -77,10 +77,10 @@ function Dashboard() {
} }
const newWindow = window.open(session?.data?.data, "_blank", "noopener,noreferrer"); const newWindow = window.open(session?.data?.data, "_blank", "noopener,noreferrer");
if (!newWindow || newWindow.closed || typeof newWindow.closed === 'undefined') { // if (!newWindow || newWindow.closed || typeof newWindow.closed === 'undefined') {
// Fallback in case popup is blocked // // Fallback in case popup is blocked
window.location.href = session?.data?.data; // window.location.href = session?.data?.data;
} // }
} }
// if(status=="payment_due"){ // if(status=="payment_due"){

View File

@ -395,10 +395,10 @@ function YourDetailsForm() {
pushNotification(response?.data?.message, NOTIFICATION.SUCCESS); pushNotification(response?.data?.message, NOTIFICATION.SUCCESS);
// open new page for stripe payment from url // open new page for stripe payment from url
const newWindow = window.open(response?.data?.data, "_blank", "noopener,noreferrer"); const newWindow = window.open(response?.data?.data, "_blank", "noopener,noreferrer");
if (!newWindow || newWindow.closed || typeof newWindow.closed === 'undefined') { // if (!newWindow || newWindow.closed || typeof newWindow.closed === 'undefined') {
// Fallback in case popup is blocked // // Fallback in case popup is blocked
window.location.href = response?.data?.data; // window.location.href = response?.data?.data;
} // }
dispatch(resetFormData()); dispatch(resetFormData());
navigate("/"); navigate("/");
} catch (error) { } catch (error) {

View File

@ -234,7 +234,7 @@ function Users() {
return ( return (
<Chip <Chip
key={index} key={index}
label={label} label={label.charAt(0).toUpperCase() + label.slice(1)}
size="small" size="small"
variant="outlined" variant="outlined"
sx={{ sx={{
@ -295,7 +295,7 @@ function Users() {
return ( return (
<Box> <Box>
<PageHeader <PageHeader
pageTitle="Doctors/Nurses List" pageTitle="Doctors/Nurses Management"
addButtonTitle="Add Doctor/Nurse" addButtonTitle="Add Doctor/Nurse"
onAddButtonClick={handleDialog} onAddButtonClick={handleDialog}
addButtonIcon={<AddIcon />} addButtonIcon={<AddIcon />}