diff --git a/.scannerwork/.sonar_lock b/.scannerwork/.sonar_lock new file mode 100644 index 00000000..e69de29b diff --git a/.scannerwork/report-task.txt b/.scannerwork/report-task.txt new file mode 100644 index 00000000..df1f2fb1 --- /dev/null +++ b/.scannerwork/report-task.txt @@ -0,0 +1,6 @@ +projectKey=pms-react +serverUrl=https://sonar.marcoaiot.com +serverVersion=25.5.0.107428 +dashboardUrl=https://sonar.marcoaiot.com/dashboard?id=pms-react +ceTaskId=ad6ba36a-08cb-400b-903e-94f173cac03f +ceTaskUrl=https://sonar.marcoaiot.com/api/ce/task?id=ad6ba36a-08cb-400b-903e-94f173cac03f diff --git a/package-lock.json b/package-lock.json index 75c151b9..dfe50b1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,7 @@ "react-router-dom": "^6.20.1", "react-toastify": "^11.0.2", "sort-by": "^1.2.0", + "swiper": "^11.2.10", "xlsx": "^0.18.5", "zod": "^3.24.1" }, @@ -5547,6 +5548,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swiper": { + "version": "11.2.10", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.2.10.tgz", + "integrity": "sha512-RMeVUUjTQH+6N3ckimK93oxz6Sn5la4aDlgPzB+rBrG/smPdCTicXyhxa+woIpopz+jewEloiEE3lKo1h9w2YQ==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/swiperjs" + }, + { + "type": "open_collective", + "url": "http://opencollective.com/swiper" + } + ], + "engines": { + "node": ">= 4.7.0" + } + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", diff --git a/package.json b/package.json index 33e1f019..02c59115 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "react-router-dom": "^6.20.1", "react-toastify": "^11.0.2", "sort-by": "^1.2.0", + "swiper": "^11.2.10", "xlsx": "^0.18.5", "zod": "^3.24.1" }, diff --git a/public/assets/css/default.css b/public/assets/css/default.css index 2abd37ee..db070129 100644 --- a/public/assets/css/default.css +++ b/public/assets/css/default.css @@ -30,9 +30,7 @@ width: 45px; } -.app-brand-logo-login { - width: 100px; -} + .app-brand-logo-border { border: 1px solid #d5d5d5; @@ -164,3 +162,24 @@ thead tr { border-top: 1px solid white; } + +.app-brand-logo-login { + max-width: 50px; /* default for mobile */ + height: auto; /* keep aspect ratio */ +} + + +/* Tablet and up (≥768px) */ +@media (min-width: 768px) { + .app-brand-logo-login { + max-width: 60px; + } +} + +/* Desktop and up (≥1200px) */ +@media (min-width: 1200px) { + .app-brand-logo-login { + max-width: 80px; + } +} + diff --git a/public/assets/vendor/css/core.css b/public/assets/vendor/css/core.css index 6e3d5d14..9be75669 100644 --- a/public/assets/vendor/css/core.css +++ b/public/assets/vendor/css/core.css @@ -32544,3 +32544,29 @@ body:not(.modal-open) .layout-content-navbar .layout-navbar { var(--bs-dark-contrast) ); } + +/* App colors classes */ +.bg-gray-60{ + background-color:var(--bs-gray-60) +} +.text-gray-60{ + color:var(--bs-gray-60) +} +.bg-blue { + background-color:var(--bs-blue) +} +.text-blue{ + color:var(--bs-blue) +} +.bg-indigo { + background-color:var(--bs-indigo) +} +.text-indigo{ + color:var(--bs-indigo) +} +.bg-red { + background-color:var(--bs-red) +} +.text-red{ + color:var(--bs-red) +} \ No newline at end of file diff --git a/public/img/front-pages/backgrounds/cta-bg-dark.png b/public/img/front-pages/backgrounds/cta-bg-dark.png new file mode 100644 index 00000000..7c4e84ae Binary files /dev/null and b/public/img/front-pages/backgrounds/cta-bg-dark.png differ diff --git a/public/img/front-pages/backgrounds/cta-bg-light.png b/public/img/front-pages/backgrounds/cta-bg-light.png new file mode 100644 index 00000000..f2cdb6fb Binary files /dev/null and b/public/img/front-pages/backgrounds/cta-bg-light.png differ diff --git a/public/img/front-pages/backgrounds/footer-bg-dark.png b/public/img/front-pages/backgrounds/footer-bg-dark.png new file mode 100644 index 00000000..150c6ee6 Binary files /dev/null and b/public/img/front-pages/backgrounds/footer-bg-dark.png differ diff --git a/public/img/front-pages/backgrounds/footer-bg-light.png b/public/img/front-pages/backgrounds/footer-bg-light.png new file mode 100644 index 00000000..ff217349 Binary files /dev/null and b/public/img/front-pages/backgrounds/footer-bg-light.png differ diff --git a/public/img/front-pages/backgrounds/footer-bg.png b/public/img/front-pages/backgrounds/footer-bg.png new file mode 100644 index 00000000..5890f0d6 Binary files /dev/null and b/public/img/front-pages/backgrounds/footer-bg.png differ diff --git a/public/img/front-pages/backgrounds/hero-bg.png b/public/img/front-pages/backgrounds/hero-bg.png new file mode 100644 index 00000000..7d175c58 Binary files /dev/null and b/public/img/front-pages/backgrounds/hero-bg.png differ diff --git a/public/img/front-pages/branding/logo-1.png b/public/img/front-pages/branding/logo-1.png new file mode 100644 index 00000000..7f551d70 Binary files /dev/null and b/public/img/front-pages/branding/logo-1.png differ diff --git a/public/img/front-pages/branding/logo-2.png b/public/img/front-pages/branding/logo-2.png new file mode 100644 index 00000000..5e3f2698 Binary files /dev/null and b/public/img/front-pages/branding/logo-2.png differ diff --git a/public/img/front-pages/branding/logo-3.png b/public/img/front-pages/branding/logo-3.png new file mode 100644 index 00000000..e854e939 Binary files /dev/null and b/public/img/front-pages/branding/logo-3.png differ diff --git a/public/img/front-pages/branding/logo-4.png b/public/img/front-pages/branding/logo-4.png new file mode 100644 index 00000000..6c5d3f3c Binary files /dev/null and b/public/img/front-pages/branding/logo-4.png differ diff --git a/public/img/front-pages/branding/logo-5.png b/public/img/front-pages/branding/logo-5.png new file mode 100644 index 00000000..bf3cc14e Binary files /dev/null and b/public/img/front-pages/branding/logo-5.png differ diff --git a/public/img/front-pages/branding/logo-6.png b/public/img/front-pages/branding/logo-6.png new file mode 100644 index 00000000..99980b2a Binary files /dev/null and b/public/img/front-pages/branding/logo-6.png differ diff --git a/public/img/front-pages/branding/logo_1-dark.png b/public/img/front-pages/branding/logo_1-dark.png new file mode 100644 index 00000000..cb1a58d2 Binary files /dev/null and b/public/img/front-pages/branding/logo_1-dark.png differ diff --git a/public/img/front-pages/branding/logo_1-light.png b/public/img/front-pages/branding/logo_1-light.png new file mode 100644 index 00000000..e0308e90 Binary files /dev/null and b/public/img/front-pages/branding/logo_1-light.png differ diff --git a/public/img/front-pages/branding/logo_2-dark.png b/public/img/front-pages/branding/logo_2-dark.png new file mode 100644 index 00000000..f5e92478 Binary files /dev/null and b/public/img/front-pages/branding/logo_2-dark.png differ diff --git a/public/img/front-pages/branding/logo_2-light.png b/public/img/front-pages/branding/logo_2-light.png new file mode 100644 index 00000000..719e6103 Binary files /dev/null and b/public/img/front-pages/branding/logo_2-light.png differ diff --git a/public/img/front-pages/branding/logo_3-dark.png b/public/img/front-pages/branding/logo_3-dark.png new file mode 100644 index 00000000..27c68e49 Binary files /dev/null and b/public/img/front-pages/branding/logo_3-dark.png differ diff --git a/public/img/front-pages/branding/logo_3-light.png b/public/img/front-pages/branding/logo_3-light.png new file mode 100644 index 00000000..5ec4f174 Binary files /dev/null and b/public/img/front-pages/branding/logo_3-light.png differ diff --git a/public/img/front-pages/branding/logo_4-dark.png b/public/img/front-pages/branding/logo_4-dark.png new file mode 100644 index 00000000..3e5bfc3d Binary files /dev/null and b/public/img/front-pages/branding/logo_4-dark.png differ diff --git a/public/img/front-pages/branding/logo_4-light.png b/public/img/front-pages/branding/logo_4-light.png new file mode 100644 index 00000000..0929f535 Binary files /dev/null and b/public/img/front-pages/branding/logo_4-light.png differ diff --git a/public/img/front-pages/branding/logo_5-dark.png b/public/img/front-pages/branding/logo_5-dark.png new file mode 100644 index 00000000..34342001 Binary files /dev/null and b/public/img/front-pages/branding/logo_5-dark.png differ diff --git a/public/img/front-pages/branding/logo_5-light.png b/public/img/front-pages/branding/logo_5-light.png new file mode 100644 index 00000000..deb1071f Binary files /dev/null and b/public/img/front-pages/branding/logo_5-light.png differ diff --git a/public/img/front-pages/icons/Join-community-arrow.png b/public/img/front-pages/icons/Join-community-arrow.png new file mode 100644 index 00000000..9bde454a Binary files /dev/null and b/public/img/front-pages/icons/Join-community-arrow.png differ diff --git a/public/img/front-pages/icons/check-warning.svg b/public/img/front-pages/icons/check-warning.svg new file mode 100644 index 00000000..4c16161c --- /dev/null +++ b/public/img/front-pages/icons/check-warning.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/img/front-pages/icons/check.svg b/public/img/front-pages/icons/check.svg new file mode 100644 index 00000000..59b5961e --- /dev/null +++ b/public/img/front-pages/icons/check.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/img/front-pages/icons/contact-border.png b/public/img/front-pages/icons/contact-border.png new file mode 100644 index 00000000..1eb721d6 Binary files /dev/null and b/public/img/front-pages/icons/contact-border.png differ diff --git a/public/img/front-pages/icons/diamond-info.svg b/public/img/front-pages/icons/diamond-info.svg new file mode 100644 index 00000000..5f24f9ef --- /dev/null +++ b/public/img/front-pages/icons/diamond-info.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/img/front-pages/icons/facebook.svg b/public/img/front-pages/icons/facebook.svg new file mode 100644 index 00000000..42672a2d --- /dev/null +++ b/public/img/front-pages/icons/facebook.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/img/front-pages/icons/github.svg b/public/img/front-pages/icons/github.svg new file mode 100644 index 00000000..75bdf8d1 --- /dev/null +++ b/public/img/front-pages/icons/github.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/img/front-pages/icons/instagram.svg b/public/img/front-pages/icons/instagram.svg new file mode 100644 index 00000000..9a6830c8 --- /dev/null +++ b/public/img/front-pages/icons/instagram.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/public/img/front-pages/icons/keyboard.svg b/public/img/front-pages/icons/keyboard.svg new file mode 100644 index 00000000..dd6b8775 --- /dev/null +++ b/public/img/front-pages/icons/keyboard.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/img/front-pages/icons/laptop.svg b/public/img/front-pages/icons/laptop.svg new file mode 100644 index 00000000..befca175 --- /dev/null +++ b/public/img/front-pages/icons/laptop.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/img/front-pages/icons/paper-airplane.png b/public/img/front-pages/icons/paper-airplane.png new file mode 100644 index 00000000..a4911dc4 Binary files /dev/null and b/public/img/front-pages/icons/paper-airplane.png differ diff --git a/public/img/front-pages/icons/paper.svg b/public/img/front-pages/icons/paper.svg new file mode 100644 index 00000000..6d933f2a --- /dev/null +++ b/public/img/front-pages/icons/paper.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/img/front-pages/icons/plane.png b/public/img/front-pages/icons/plane.png new file mode 100644 index 00000000..497cc1e4 Binary files /dev/null and b/public/img/front-pages/icons/plane.png differ diff --git a/public/img/front-pages/icons/pricing-plans-arrow.png b/public/img/front-pages/icons/pricing-plans-arrow.png new file mode 100644 index 00000000..ed8f60bb Binary files /dev/null and b/public/img/front-pages/icons/pricing-plans-arrow.png differ diff --git a/public/img/front-pages/icons/rocket.svg b/public/img/front-pages/icons/rocket.svg new file mode 100644 index 00000000..700323aa --- /dev/null +++ b/public/img/front-pages/icons/rocket.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/img/front-pages/icons/section-title-icon.png b/public/img/front-pages/icons/section-title-icon.png new file mode 100644 index 00000000..6e8d1730 Binary files /dev/null and b/public/img/front-pages/icons/section-title-icon.png differ diff --git a/public/img/front-pages/icons/shuttle-rocket.png b/public/img/front-pages/icons/shuttle-rocket.png new file mode 100644 index 00000000..154b17e7 Binary files /dev/null and b/public/img/front-pages/icons/shuttle-rocket.png differ diff --git a/public/img/front-pages/icons/twitter.svg b/public/img/front-pages/icons/twitter.svg new file mode 100644 index 00000000..78fa4dc2 --- /dev/null +++ b/public/img/front-pages/icons/twitter.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/img/front-pages/icons/user-success.svg b/public/img/front-pages/icons/user-success.svg new file mode 100644 index 00000000..32d4b3bb --- /dev/null +++ b/public/img/front-pages/icons/user-success.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/img/front-pages/icons/user.svg b/public/img/front-pages/icons/user.svg new file mode 100644 index 00000000..af4eac79 --- /dev/null +++ b/public/img/front-pages/icons/user.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/img/front-pages/landing-page/apple-icon.png b/public/img/front-pages/landing-page/apple-icon.png new file mode 100644 index 00000000..82527801 Binary files /dev/null and b/public/img/front-pages/landing-page/apple-icon.png differ diff --git a/public/img/front-pages/landing-page/contact-customer-service.png b/public/img/front-pages/landing-page/contact-customer-service.png new file mode 100644 index 00000000..4e5aaaad Binary files /dev/null and b/public/img/front-pages/landing-page/contact-customer-service.png differ diff --git a/public/img/front-pages/landing-page/cta-dashboard.png b/public/img/front-pages/landing-page/cta-dashboard.png new file mode 100644 index 00000000..9dcb642f Binary files /dev/null and b/public/img/front-pages/landing-page/cta-dashboard.png differ diff --git a/public/img/front-pages/landing-page/dashboard-light-01.png b/public/img/front-pages/landing-page/dashboard-light-01.png new file mode 100644 index 00000000..8e1d4956 Binary files /dev/null and b/public/img/front-pages/landing-page/dashboard-light-01.png differ diff --git a/public/img/front-pages/landing-page/dashboard-light-02.png b/public/img/front-pages/landing-page/dashboard-light-02.png new file mode 100644 index 00000000..ede59aed Binary files /dev/null and b/public/img/front-pages/landing-page/dashboard-light-02.png differ diff --git a/public/img/front-pages/landing-page/dashboard-light-03.png b/public/img/front-pages/landing-page/dashboard-light-03.png new file mode 100644 index 00000000..1e45e519 Binary files /dev/null and b/public/img/front-pages/landing-page/dashboard-light-03.png differ diff --git a/public/img/front-pages/landing-page/dashboard-light-04.png b/public/img/front-pages/landing-page/dashboard-light-04.png new file mode 100644 index 00000000..998d30ea Binary files /dev/null and b/public/img/front-pages/landing-page/dashboard-light-04.png differ diff --git a/public/img/front-pages/landing-page/dashboard-light-05.png b/public/img/front-pages/landing-page/dashboard-light-05.png new file mode 100644 index 00000000..c7e6f5ac Binary files /dev/null and b/public/img/front-pages/landing-page/dashboard-light-05.png differ diff --git a/public/img/front-pages/landing-page/dashboard-light-06.png b/public/img/front-pages/landing-page/dashboard-light-06.png new file mode 100644 index 00000000..386d7289 Binary files /dev/null and b/public/img/front-pages/landing-page/dashboard-light-06.png differ diff --git a/public/img/front-pages/landing-page/dashboard-light-07.png b/public/img/front-pages/landing-page/dashboard-light-07.png new file mode 100644 index 00000000..b358f986 Binary files /dev/null and b/public/img/front-pages/landing-page/dashboard-light-07.png differ diff --git a/public/img/front-pages/landing-page/dashboard-light-08.png b/public/img/front-pages/landing-page/dashboard-light-08.png new file mode 100644 index 00000000..2ae124a9 Binary files /dev/null and b/public/img/front-pages/landing-page/dashboard-light-08.png differ diff --git a/public/img/front-pages/landing-page/faq-boy-with-logos.png b/public/img/front-pages/landing-page/faq-boy-with-logos.png new file mode 100644 index 00000000..b64dbfcc Binary files /dev/null and b/public/img/front-pages/landing-page/faq-boy-with-logos.png differ diff --git a/public/img/front-pages/landing-page/google-play-icon.png b/public/img/front-pages/landing-page/google-play-icon.png new file mode 100644 index 00000000..117bcb16 Binary files /dev/null and b/public/img/front-pages/landing-page/google-play-icon.png differ diff --git a/public/img/front-pages/landing-page/hero-dashboard-dark.png b/public/img/front-pages/landing-page/hero-dashboard-dark.png new file mode 100644 index 00000000..e035ae98 Binary files /dev/null and b/public/img/front-pages/landing-page/hero-dashboard-dark.png differ diff --git a/public/img/front-pages/landing-page/hero-dashboard-light1.png b/public/img/front-pages/landing-page/hero-dashboard-light1.png new file mode 100644 index 00000000..b4f5fe55 Binary files /dev/null and b/public/img/front-pages/landing-page/hero-dashboard-light1.png differ diff --git a/public/img/front-pages/landing-page/hero-elements-dark.png b/public/img/front-pages/landing-page/hero-elements-dark.png new file mode 100644 index 00000000..af1f5506 Binary files /dev/null and b/public/img/front-pages/landing-page/hero-elements-dark.png differ diff --git a/public/img/front-pages/landing-page/hero-elements-light.png b/public/img/front-pages/landing-page/hero-elements-light.png new file mode 100644 index 00000000..99f88901 Binary files /dev/null and b/public/img/front-pages/landing-page/hero-elements-light.png differ diff --git a/public/img/front-pages/landing-page/team-member-1.png b/public/img/front-pages/landing-page/team-member-1.png new file mode 100644 index 00000000..2a007f12 Binary files /dev/null and b/public/img/front-pages/landing-page/team-member-1.png differ diff --git a/public/img/front-pages/landing-page/team-member-2.png b/public/img/front-pages/landing-page/team-member-2.png new file mode 100644 index 00000000..b1b7e7c0 Binary files /dev/null and b/public/img/front-pages/landing-page/team-member-2.png differ diff --git a/public/img/front-pages/landing-page/team-member-3.png b/public/img/front-pages/landing-page/team-member-3.png new file mode 100644 index 00000000..805b2825 Binary files /dev/null and b/public/img/front-pages/landing-page/team-member-3.png differ diff --git a/public/img/front-pages/landing-page/team-member-4.png b/public/img/front-pages/landing-page/team-member-4.png new file mode 100644 index 00000000..8718f3c1 Binary files /dev/null and b/public/img/front-pages/landing-page/team-member-4.png differ diff --git a/public/img/front-pages/misc/checkout-image.png b/public/img/front-pages/misc/checkout-image.png new file mode 100644 index 00000000..720bfc48 Binary files /dev/null and b/public/img/front-pages/misc/checkout-image.png differ diff --git a/public/img/front-pages/misc/nav-item-col-img.png b/public/img/front-pages/misc/nav-item-col-img.png new file mode 100644 index 00000000..5e51e3be Binary files /dev/null and b/public/img/front-pages/misc/nav-item-col-img.png differ diff --git a/public/img/front-pages/misc/product-image.png b/public/img/front-pages/misc/product-image.png new file mode 100644 index 00000000..25f511b9 Binary files /dev/null and b/public/img/front-pages/misc/product-image.png differ diff --git a/public/img/illustrations/girl-unlock-password-light.png b/public/img/illustrations/girl-unlock-password-light.png new file mode 100644 index 00000000..18f4b274 Binary files /dev/null and b/public/img/illustrations/girl-unlock-password-light.png differ diff --git a/public/img/illustrations/registration.jpg b/public/img/illustrations/registration.jpg new file mode 100644 index 00000000..69cf7b8e Binary files /dev/null and b/public/img/illustrations/registration.jpg differ diff --git a/public/img/illustrations/worker_01.svg b/public/img/illustrations/worker_01.svg new file mode 100644 index 00000000..2170c2f4 --- /dev/null +++ b/public/img/illustrations/worker_01.svg @@ -0,0 +1,4955 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/illustrations/worker_02.jpg b/public/img/illustrations/worker_02.jpg new file mode 100644 index 00000000..274c55c3 Binary files /dev/null and b/public/img/illustrations/worker_02.jpg differ diff --git a/public/img/illustrations/worker_02.svg b/public/img/illustrations/worker_02.svg new file mode 100644 index 00000000..c673e01c --- /dev/null +++ b/public/img/illustrations/worker_02.svg @@ -0,0 +1,1117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/illustrations/worker_03.jpg b/public/img/illustrations/worker_03.jpg new file mode 100644 index 00000000..99c9be24 Binary files /dev/null and b/public/img/illustrations/worker_03.jpg differ diff --git a/public/img/illustrations/worker_03.png b/public/img/illustrations/worker_03.png new file mode 100644 index 00000000..d5fdab98 Binary files /dev/null and b/public/img/illustrations/worker_03.png differ diff --git a/public/img/illustrations/worker_03.svg b/public/img/illustrations/worker_03.svg new file mode 100644 index 00000000..ee552ecf --- /dev/null +++ b/public/img/illustrations/worker_03.svg @@ -0,0 +1,383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/Activities/Attendance.jsx b/src/components/Activities/Attendance.jsx index eb7dc500..6d751b12 100644 --- a/src/components/Activities/Attendance.jsx +++ b/src/components/Activities/Attendance.jsx @@ -114,7 +114,10 @@ const Attendance = ({ getRole, handleModalData, searchTerm }) => { return ( <> -
+
Date : {formatUTCToLocalTime(todayDate)}
@@ -209,7 +212,11 @@ const Attendance = ({ getRole, handleModalData, searchTerm }) => { ))} {!attendance && ( - No employees assigned to the project! + + + No employees assigned to the project! + + )} @@ -258,7 +265,10 @@ const Attendance = ({ getRole, handleModalData, searchTerm }) => { )} ) : ( -
+
{searchTerm ? "No results found for your search." : attendanceList.length === 0 diff --git a/src/components/Activities/AttendcesLogs.jsx b/src/components/Activities/AttendcesLogs.jsx index 681783be..faf4bdc5 100644 --- a/src/components/Activities/AttendcesLogs.jsx +++ b/src/components/Activities/AttendcesLogs.jsx @@ -42,7 +42,7 @@ const AttendanceLog = ({ handleModalData, searchTerm }) => { const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" }); const dispatch = useDispatch(); const [loading, setLoading] = useState(false); - const [showPending,setShowPending] = useState(false) + const [showPending, setShowPending] = useState(false) const [isRefreshing, setIsRefreshing] = useState(false); const [processedData, setProcessedData] = useState([]); @@ -245,17 +245,16 @@ const AttendanceLog = ({ handleModalData, searchTerm }) => {
refetch()} />
-
+
{isLoading ? ( -
+

Loading...

) : filteredSearchData?.length > 0 ? ( @@ -284,9 +283,9 @@ const AttendanceLog = ({ handleModalData, searchTerm }) => { const previousAttendance = arr[index - 1]; const previousDate = previousAttendance ? moment( - previousAttendance.checkInTime || - previousAttendance.checkOutTime - ).format("YYYY-MM-DD") + previousAttendance.checkInTime || + previousAttendance.checkOutTime + ).format("YYYY-MM-DD") : null; if (!previousDate || currentDate !== previousDate) { @@ -346,12 +345,15 @@ const AttendanceLog = ({ handleModalData, searchTerm }) => { ) : ( -
No Record Available !
+
No Record Available !
)}
{paginatedAttendances?.length == 0 && filteredSearchData?.length > 0 && ( -
- No Pending Record Available ! +
+ No Record Available !
)} {filteredSearchData.length > ITEMS_PER_PAGE && ( @@ -369,9 +371,8 @@ const AttendanceLog = ({ handleModalData, searchTerm }) => { (pageNumber) => (
  • +
    +
    ); diff --git a/src/components/Activities/Regularization.jsx b/src/components/Activities/Regularization.jsx index cdcd3972..82c906b5 100644 --- a/src/components/Activities/Regularization.jsx +++ b/src/components/Activities/Regularization.jsx @@ -87,9 +87,9 @@ const Regularization = ({ handleRequest, searchTerm }) => { }, [employeeHandler]); return ( -
    +
    {loading ? ( -
    +

    Loading...

    ) : currentItems?.length > 0 ? ( @@ -143,9 +143,14 @@ const Regularization = ({ handleRequest, searchTerm }) => { ) : ( -
    +
    - {searchTerm ? "No results found for your search." : "No Requests Found !"} + {searchTerm + ? "No results found for your search." + : "No Requests Found !"}
    )} @@ -163,9 +168,8 @@ const Regularization = ({ handleRequest, searchTerm }) => { {[...Array(totalPages)].map((_, index) => (
  • ))}
  • -
    - +
    + +
    ); }; - export default ReportTask; \ No newline at end of file +export default ReportTask; \ No newline at end of file diff --git a/src/components/Activities/ReportTaskComments.jsx b/src/components/Activities/ReportTaskComments.jsx index c48f9796..60a81ff3 100644 --- a/src/components/Activities/ReportTaskComments.jsx +++ b/src/components/Activities/ReportTaskComments.jsx @@ -10,6 +10,7 @@ import { getBgClassFromHash } from "../../utils/projectStatus"; import { cacheData, getCachedData } from "../../slices/apiDataManager"; import ImagePreview from "../common/ImagePreview"; import { useAuditStatus, useSubmitTaskComment } from "../../hooks/useTasks"; +import Label from "../common/Label"; const ReportTaskComments = ({ commentsData, @@ -291,10 +292,10 @@ const ReportTaskComments = ({

    )}
    -
    -
    + return ( +
    + {/* Header */} +
    +
    +
    Attendance Overview
    +

    Role-wise present count

    +
    +
    + + + +
    +
    {/* Content */}
    diff --git a/src/components/Dashboard/ProjectCompletionChart.jsx b/src/components/Dashboard/ProjectCompletionChart.jsx index f0c85179..8ce4b13a 100644 --- a/src/components/Dashboard/ProjectCompletionChart.jsx +++ b/src/components/Dashboard/ProjectCompletionChart.jsx @@ -19,7 +19,7 @@ const ProjectCompletionChart = () => {
    -
    Projects
    +
    Projects

    Projects Completion Status

    diff --git a/src/components/Dashboard/ProjectProgressChart.jsx b/src/components/Dashboard/ProjectProgressChart.jsx index f80bb0d5..61747f6c 100644 --- a/src/components/Dashboard/ProjectProgressChart.jsx +++ b/src/components/Dashboard/ProjectProgressChart.jsx @@ -90,7 +90,7 @@ const ProjectProgressChart = ({
    {/* Left: Title */}
    -
    Project Progress
    +
    Project Progress

    Progress Overview by Project

    diff --git a/src/components/Directory/CardViewDirectory.jsx b/src/components/Directory/CardViewDirectory.jsx index b623ef0e..21ceea84 100644 --- a/src/components/Directory/CardViewDirectory.jsx +++ b/src/components/Directory/CardViewDirectory.jsx @@ -25,8 +25,9 @@ const CardViewDirectory = ({
    { if (IsActive) { setIsOpenModalNote(true); @@ -89,10 +90,11 @@ const CardViewDirectory = ({ )} {!IsActive && ( { setDirActions({ action: false, id: contact.id }); @@ -113,8 +115,9 @@ const CardViewDirectory = ({
    { if (IsActive) { setIsOpenModalNote(true); @@ -126,7 +129,7 @@ const CardViewDirectory = ({ {contact.designation && (
    • - +
    • {contact.designation} diff --git a/src/components/Directory/ManageBucket.jsx b/src/components/Directory/ManageBucket.jsx index 58344a15..5cbd89c4 100644 --- a/src/components/Directory/ManageBucket.jsx +++ b/src/components/Directory/ManageBucket.jsx @@ -198,23 +198,14 @@ const ManageBucket = () => { return ( <> {deleteBucket && ( -
      - setDeleteBucket(null)} - /> -
      + setDeleteBucket(null)} + /> )}
      @@ -237,8 +228,9 @@ const ManageBucket = () => { onChange={(e) => setSearchTerm(e.target.value)} /> refetch()} /> @@ -247,8 +239,9 @@ const ManageBucket = () => {
      )} - {!loading && buckets.length > 0 && sortedBucktesList.length === 0 && ( -
      -
      - No matching buckets found. + {!loading && + buckets.length > 0 && + sortedBucktesList.length === 0 && ( +
      +
      + No matching buckets found. +
      -
      - )} + )} {!loading && sortedBucktesList.map((bucket) => (
      @@ -305,29 +300,29 @@ const ManageBucket = () => { {(DirManager || DirAdmin || bucket?.createdBy?.id === - profile?.employeeInfo?.id) && ( -
      - { - select_bucket(bucket); - setAction_bucket(true); - const initialSelectedEmployees = employeesList - .filter((emp) => - bucket.employeeIds?.includes( - emp.employeeId - ) + profile?.employeeInfo?.id) && ( +
      + { + select_bucket(bucket); + setAction_bucket(true); + const initialSelectedEmployees = employeesList + .filter((emp) => + bucket.employeeIds?.includes( + emp.employeeId ) - .map((emp) => ({ ...emp, isActive: true })); - setSelectEmployee(initialSelectedEmployees); - }} - > - setDeleteBucket(bucket?.id)} - > -
      - )} + ) + .map((emp) => ({ ...emp, isActive: true })); + setSelectEmployee(initialSelectedEmployees); + }} + >
      + setDeleteBucket(bucket?.id)} + > +
      + )}
      Contacts:{" "} diff --git a/src/components/Directory/ManageDirectory.jsx b/src/components/Directory/ManageDirectory.jsx index 5c858815..d03139a9 100644 --- a/src/components/Directory/ManageDirectory.jsx +++ b/src/components/Directory/ManageDirectory.jsx @@ -23,6 +23,7 @@ import { useProjects } from "../../hooks/useProjects"; import SelectMultiple from "../common/SelectMultiple"; import { ContactSchema } from "./DirectorySchema"; import InputSuggestions from "../common/InputSuggestion"; +import Label from "../common/Label"; const ManageDirectory = ({ submitContact, onCLosed }) => { const selectedMaster = useSelector( @@ -40,7 +41,7 @@ const ManageDirectory = ({ submitContact, onCLosed }) => { const { designationList, loading: designloading } = useDesignation(); const { contactTags, loading: Tagloading } = useContactTags(); const [IsSubmitting, setSubmitting] = useState(false); - const [showSuggestions,setShowSuggestions] = useState(false); + const [showSuggestions, setShowSuggestions] = useState(false); const [filteredDesignationList, setFilteredDesignationList] = useState([]); const dispatch = useDispatch(); @@ -132,6 +133,12 @@ const ManageDirectory = ({ submitContact, onCLosed }) => { setValue("designation", val); }; + // Handle phone number input to only allow numbers and max length of 10 + const handlePhoneInput = (e) => { + const value = e.target.value.replace(/[^0-9]/g, ""); + e.target.value = value.slice(0, 10); + }; + const toggleBucketId = (id) => { const updated = watchBucketIds?.includes(id) @@ -171,11 +178,11 @@ const ManageDirectory = ({ submitContact, onCLosed }) => {
      -
      Create New Contact
      +
      Create New Contact
      - + {
      - + {
      - + { placeholder="email@example.com" /> {index === emailFields.length - 1 ? ( - //
      - +
        {bucketsLoaging &&

        Loading...

        } @@ -475,8 +460,8 @@ const ManageDirectory = ({ submitContact, onCLosed }) => { />
      -
      - +
      + + {errors.description && ( +
      {errors.description.message}
      + )} +
      + + {/* Buttons */} +
      + + +
      + + +
      + ); +}; + +export default ManageDocument; diff --git a/src/components/Documents/VersionListSkeleton.jsx b/src/components/Documents/VersionListSkeleton.jsx new file mode 100644 index 00000000..d239315c --- /dev/null +++ b/src/components/Documents/VersionListSkeleton.jsx @@ -0,0 +1,47 @@ +import React from "react"; + +const SkeletonLine = ({ height = 16, width = "100%", className = "" }) => ( +
      +); + +const VersionListSkeleton = ({ items = 5 }) => { + return ( +
      + {[...Array(items)].map((_, idx) => ( +
      + {/* Top row: document name + version/status */} +
      + +
      + + +
      +
      + + {/* Upload by row */} +
      + + +
      + + {/* Updated at row */} +
      + +
      +
      + ))} +
      + ); +}; + +export default VersionListSkeleton; diff --git a/src/components/Documents/ViewDocument.jsx b/src/components/Documents/ViewDocument.jsx new file mode 100644 index 00000000..6405a3ed --- /dev/null +++ b/src/components/Documents/ViewDocument.jsx @@ -0,0 +1,175 @@ +import React, { useState } from "react"; +import { + useDocumentDetails, + useDocumentVersionList, + useVerifyDocument, +} from "../../hooks/useDocument"; +import { getDocuementsStatus, useDocumentContext } from "./Documents"; +import { formatUTCToLocalTime } from "../../utils/dateUtils"; +import Avatar from "../common/Avatar"; +import { + DOWNLOAD_DOCUMENT, + ITEMS_PER_PAGE, + VERIFY_DOCUMENT, +} from "../../utils/constants"; +import DocumentDetailsSkeleton from "./DocumentDetailsSkeleton "; +import { useHasUserPermission } from "../../hooks/useHasUserPermission"; +import DocumentVersionList from "./DocumentVersionList"; + +const ViewDocument = () => { + const { viewDoc, setOpenDocument } = useDocumentContext(); + const [currentPage, setCurrentPage] = useState(1); + const [showVersions, setShowVersions] = useState(false); + const canVerifyDocument = useHasUserPermission(VERIFY_DOCUMENT); + + // Document Details + const { data, isLoading, isError, error } = useDocumentDetails( + viewDoc?.document + ); + + // Document Versions (fetch only if toggle is ON) + const { + data: versionList, + isLoading: versionLoading, + } = useDocumentVersionList( + showVersions ? data?.parentAttachmentId : null, + ITEMS_PER_PAGE - 10, + currentPage + ); + + const paginate = (page) => { + if (page >= 1 && page <= (versionList?.totalPages ?? 1)) { + setCurrentPage(page); + } + }; + + // Verify / Reject + const { mutate: VerifyDoc, isPending } = useVerifyDocument(); + const VerifyDocument = () => { + VerifyDoc({ documentId: viewDoc?.document, isVerify: true }); + }; + const RejectDocument = () => { + VerifyDoc({ documentId: viewDoc?.document, isVerify: false }); + }; + + if (isLoading) return ; + if (isError) + return ( +
      +

      {error?.response?.data?.message || error?.message}

      +

      {error?.response?.status}

      +
      + ); + + return ( +
      +

      Document Details

      + + {/* Document Info Rows */} +
      +
      + + Category: + + + {data.documentType?.documentCategory?.name || "-"} + +
      +
      + + Type: + + {data.documentType?.name || "-"} +
      +
      + +
      +
      + + Document Name: + + {data.name || "-"} +
      +
      + + Document ID: + + {data.documentId || "-"} +
      +
      + +
      +
      + + Uploaded At: + + + {formatUTCToLocalTime(data.uploadedAt)} + +
      + +
      + +
      +
      + + Tags: + +
      + {data.tags?.length > 0 ? ( + data.tags.map((t, i) => ( + + {t.name} + + )) + ) : ( + - + )} +
      +
      +
      + +
      +
      + + Description: + + {data.description || "-"} +
      +
      + + {/* Toggle for Versions */} +
      +

      Documents:

      +
      + + setShowVersions(e.target.checked)} + /> +
      +
      + + +
      + ); +}; + +export default ViewDocument; \ No newline at end of file diff --git a/src/components/Employee/EmpActivities.jsx b/src/components/Employee/EmpActivities.jsx index f5d9e8c2..e79b181d 100644 --- a/src/components/Employee/EmpActivities.jsx +++ b/src/components/Employee/EmpActivities.jsx @@ -25,7 +25,7 @@ error,
      diff --git a/src/components/Employee/EmpAttendance.jsx b/src/components/Employee/EmpAttendance.jsx index 26ae9531..dfa12e98 100644 --- a/src/components/Employee/EmpAttendance.jsx +++ b/src/components/Employee/EmpAttendance.jsx @@ -128,7 +128,7 @@ const EmpAttendance = ({ employee }) => { >
      diff --git a/src/components/Employee/EmpBanner.jsx b/src/components/Employee/EmpBanner.jsx index 6cb12073..bb019bc6 100644 --- a/src/components/Employee/EmpBanner.jsx +++ b/src/components/Employee/EmpBanner.jsx @@ -3,6 +3,7 @@ import React, { useState, useEffect } from "react"; import { useChangePassword } from "../../components/Context/ChangePasswordContext"; import GlobalModel from "../common/GlobalModel"; import ManageEmployee from "./ManageEmployee"; +import { formatUTCToLocalTime } from "../../utils/dateUtils"; const EmpBanner = ({ profile, loggedInUser }) => { const { openChangePassword } = useChangePassword(); @@ -77,7 +78,7 @@ const EmpBanner = ({ profile, loggedInUser }) => { {" "} Joined on{" "} {profile?.joiningDate ? ( - new Date(profile.joiningDate).toLocaleDateString() + formatUTCToLocalTime(profile.joiningDate) ) : ( NA )} diff --git a/src/components/Employee/EmpDashboard.jsx b/src/components/Employee/EmpDashboard.jsx index b25f6803..85c97836 100644 --- a/src/components/Employee/EmpDashboard.jsx +++ b/src/components/Employee/EmpDashboard.jsx @@ -9,7 +9,6 @@ const EmpDashboard = ({ profile }) => { refetch, } = useProjectsAllocationByEmployee(profile?.id); - console.log(projectList); return ( <>
      diff --git a/src/components/Employee/EmpDocuments.jsx b/src/components/Employee/EmpDocuments.jsx index 46aa33d0..b4c8046b 100644 --- a/src/components/Employee/EmpDocuments.jsx +++ b/src/components/Employee/EmpDocuments.jsx @@ -1,10 +1,15 @@ import React, { useState, useEffect } from "react"; import { ComingSoonPage } from "../../pages/Misc/ComingSoonPage"; +import DocumentPage from "../../pages/Documents/DocumentPage"; +import Documents from "../Documents/Documents"; +import { useParams } from "react-router-dom"; +import { DOCUMENTS_ENTITIES } from "../../utils/constants"; const EmpDocuments = ({ profile, loggedInUser }) => { + const {employeeId} = useParams() return ( <> - + ); }; diff --git a/src/components/Employee/EmpOverview.jsx b/src/components/Employee/EmpOverview.jsx index 6b396745..cf4ce4af 100644 --- a/src/components/Employee/EmpOverview.jsx +++ b/src/components/Employee/EmpOverview.jsx @@ -142,13 +142,14 @@ const EmpOverview = ({ profile }) => {
      {/* Address */} -
      - +
      + - Address + Address + : - + {profile?.currentAddress || NA}
      diff --git a/src/components/Employee/EmployeeList.jsx b/src/components/Employee/EmployeeList.jsx index 2ae93d5e..5a79c6ce 100644 --- a/src/components/Employee/EmployeeList.jsx +++ b/src/components/Employee/EmployeeList.jsx @@ -4,4 +4,4 @@ const EmployeeList = () => { return
      EmployeeList
      ; }; -export default EmployeeList; +export default EmployeeList; \ No newline at end of file diff --git a/src/components/Employee/EmployeeNav.jsx b/src/components/Employee/EmployeeNav.jsx index d9a6b3e0..8c25aa22 100644 --- a/src/components/Employee/EmployeeNav.jsx +++ b/src/components/Employee/EmployeeNav.jsx @@ -1,12 +1,31 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; +import { useHasUserPermission } from "../../hooks/useHasUserPermission"; +import { VIEW_DOCUMENT } from "../../utils/constants"; +import { useProfile } from "../../hooks/useProfile"; +import { useParams } from "react-router-dom"; const EmployeeNav = ({ onPillClick, activePill }) => { + const { employeeId } = useParams(); + const [isAbleToViewDocuments, setIsAbleToViewDocuments] = useState(false); + + const canViewDocuments = useHasUserPermission(VIEW_DOCUMENT); + const { profile } = useProfile(); + + useEffect(() => { + if (profile?.employeeInfo?.id) { + setIsAbleToViewDocuments(profile.employeeInfo.id === employeeId); + } + }, [profile?.employeeInfo?.id, employeeId]); + const tabs = [ { key: "profile", icon: "bx bx-user", label: "Profile" }, { key: "attendance", icon: "bx bx-group", label: "Attendances" }, - { key: "documents", icon: "bx bx-user", label: "Documents" }, + (isAbleToViewDocuments || canViewDocuments) && { + key: "documents", + icon: "bx bx-file", + label: "Documents", + }, { key: "activities", icon: "bx bx-grid-alt", label: "Activities" }, - ]; - + ].filter(Boolean); return (
      diff --git a/src/components/Employee/ManageEmployee.jsx b/src/components/Employee/ManageEmployee.jsx index 1805220b..81a4c4d2 100644 --- a/src/components/Employee/ManageEmployee.jsx +++ b/src/components/Employee/ManageEmployee.jsx @@ -17,6 +17,8 @@ import { } from "../../slices/apiDataManager"; import { clearApiCacheKey } from "../../slices/apiCacheSlice"; import { useMutation } from "@tanstack/react-query"; +import Label from "../common/Label"; +import DatePicker from "../common/DatePicker"; const mobileNumberRegex = /^[0-9]\d{9}$/; @@ -220,10 +222,10 @@ const ManageEmployee = ({ employeeId, onClosed, IsAllEmployee }) => { return ( <>
      -

      {employee ? "Update Employee" : "Create Employee"}

      +

      {employee ? "Update Employee" : "Create Employee"}

      -
      First Name
      + {
      -
      Last Name
      + { )}
      -
      Phone Number
      + {
      -
      Gender
      +
      + {errors.birthDate && ( -
      +
      {errors.birthDate.message}
      )}
      -
      Joining Date
      +
      -
      + {errors.joiningDate && ( -
      +
      {errors.joiningDate.message}
      )} @@ -412,7 +416,7 @@ const ManageEmployee = ({ employeeId, onClosed, IsAllEmployee }) => {
      -
      Current Address
      + +
      +
      + +
      +
      + +
      +
      +
      +
      +
      + + {/* Contact Us: End */} +
      + + {/* / Sections:End */} + + {/* Footer: Start */} + + {/* Footer: End */} +
      + ); +}; +export default LandingPage; diff --git a/src/pages/TermsAndConditions/LegalInfoCard.jsx b/src/pages/TermsAndConditions/LegalInfoCard.jsx index baa5d3da..cd7c9e05 100644 --- a/src/pages/TermsAndConditions/LegalInfoCard.jsx +++ b/src/pages/TermsAndConditions/LegalInfoCard.jsx @@ -4,25 +4,10 @@ const LegalInfoPage = () => { return ( <>
      MARCO SECURE SOLUTIONS @@ -41,7 +26,7 @@ const LegalInfoPage = () => { overflowY: 'auto', flexGrow: 1, - marginBottom: '2rem', // Adds space below the card + marginBottom: '2rem', }} >

      Terms & Conditions

      diff --git a/src/pages/authentication/AuthWrapper.jsx b/src/pages/authentication/AuthWrapper.jsx index c065bac2..5c8f0eb9 100644 --- a/src/pages/authentication/AuthWrapper.jsx +++ b/src/pages/authentication/AuthWrapper.jsx @@ -4,17 +4,17 @@ import "./page-auth.css"; export const AuthWrapper = ({ children }) => { return (
      -
      + {/*
      -
      +
      */}
      -
      +
      - + marco-logo { /> -
      + {/*
      */} {children}
      -
      -
      + //
      + //
      ); -}; +}; \ No newline at end of file diff --git a/src/pages/authentication/ForgotPasswordPage.jsx b/src/pages/authentication/ForgotPasswordPage.jsx index 508b7a56..8a6fc608 100644 --- a/src/pages/authentication/ForgotPasswordPage.jsx +++ b/src/pages/authentication/ForgotPasswordPage.jsx @@ -1,89 +1,88 @@ import { useState } from "react"; -import {Link} from "react-router-dom"; +import { Link } from "react-router-dom"; import { AuthWrapper } from "./AuthWrapper" import "./page-auth.css"; import AuthRepository from "../../repositories/AuthRepository"; import showToast from "../../services/toastService"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; -import {z} from "zod"; +import { z } from "zod"; -const forgotPassSceham = z.object( { +const forgotPassSceham = z.object({ email: z.string().email(), -} ) +}) const ForgotPasswordPage = () => { - const[loding,setLoading] = useState(false) + const [loding, setLoading] = useState(false) - const {register, + const { register, handleSubmit, formState: { errors }, reset, - getValues } = useForm( { - resolver: zodResolver( forgotPassSceham ), - defaultValues: { - email:"" - } - }) + getValues } = useForm({ + resolver: zodResolver(forgotPassSceham), + defaultValues: { + email: "" + } + }) - const onSubmit = async (data) => - { - try - { + const onSubmit = async (data) => { + try { setLoading(true) - const response = await AuthRepository.forgotPassword(data) - if ( response.data && response.success ) - showToast( "verification email has been sent to your registered email address", "success" ) + const response = await AuthRepository.forgotPassword(data) + if (response.data && response.success) + showToast("verification email has been sent to your registered email address", "success") reset() - setLoading( false ) - } catch ( err ) - { + setLoading(false) + } catch (err) { reset() - if(err.response.status === 404){ - showToast( "verification email has been sent to your registered email address", "success" ) - }else{ - showToast("Something wrong","error") - } - + if (err.response.status === 404) { + showToast("verification email has been sent to your registered email address", "success") + } else { + showToast("Something wrong", "error") + } + setLoading(false) } } return ( - -

      Forgot Password? 🔒

      -

      - Enter your email and we'll send you instructions to reset your password -

      -
      -
      - - - {errors.email && ( -
      - {errors.email.message} -
      - )} -
      - -
      -
      +
      +
      +

      Forgot Password? 🔒

      +

      + Enter your email and we'll send you instructions to reset your password +

      + +
      +
      + + + {errors.email && ( +
      + {errors.email.message} +
      + )} +
      + +
      +
      { Back to login
      - + + {/* Footer Text */} + +
      +
      ); }; -export default ForgotPasswordPage; +export default ForgotPasswordPage; \ No newline at end of file diff --git a/src/pages/authentication/LoginPage.jsx b/src/pages/authentication/LoginPage.jsx index 3f91e29a..9240e33d 100644 --- a/src/pages/authentication/LoginPage.jsx +++ b/src/pages/authentication/LoginPage.jsx @@ -1,70 +1,54 @@ import { useEffect, useState } from "react"; -import { Link } from "react-router-dom"; -import { AuthWrapper } from "./AuthWrapper"; -import { useNavigate } from "react-router-dom"; -import "./page-auth.css"; +import { Link, useNavigate } from "react-router-dom"; import AuthRepository from "../../repositories/AuthRepository"; import showToast from "../../services/toastService"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; +import { AuthWrapper } from "./AuthWrapper"; const LoginPage = () => { const navigate = useNavigate(); const [loading, setLoading] = useState(false); const [hidepass, setHidepass] = useState(true); const [IsLoginWithOTP, setLoginWithOtp] = useState(false); - const [IsTriedOTPThrough, setIsTriedOTPThrough] = useState(false); const now = Date.now(); const loginSchema = IsLoginWithOTP ? z.object({ - username: z.string() - .trim() - .email({ message: "Valid email required" }), - }) + username: z.string().email({ message: "Valid email required" }), + }) : z.object({ - username: z.string() - .trim() - .email({ message: "Valid email required" }), - password: z.string() - .trim() - .min(1, { message: "Password required" }), - rememberMe: z.boolean(), - }); + username: z.string().email({ message: "Valid email required" }), + password: z.string().min(1, { message: "Password required" }), + rememberMe: z.boolean(), + }); const { register, handleSubmit, formState: { errors }, - reset, - getValues, } = useForm({ resolver: zodResolver(loginSchema), }); const onSubmit = async (data) => { setLoading(true); - try { - const username = data.username.trim(); - const password = data.password?.trim(); - if (!IsLoginWithOTP) { const userCredential = { - username, - password, + username: data.username, + password: data.password, }; - const response = await AuthRepository.login(userCredential); localStorage.setItem("jwtToken", response.data.token); localStorage.setItem("refreshToken", response.data.refreshToken); setLoading(false); navigate("/dashboard"); } else { - await AuthRepository.sendOTP({ email: username }); + await AuthRepository.sendOTP({ email: data.username }); showToast("OTP has been sent to your email.", "success"); - localStorage.setItem("otpUsername", username); + localStorage.setItem("otpUsername", data.username); localStorage.setItem("otpSentTime", now.toString()); navigate("/auth/login-otp"); } @@ -74,7 +58,6 @@ const LoginPage = () => { } }; - useEffect(() => { const otpSentTime = localStorage.getItem("otpSentTime"); if ( @@ -85,138 +68,150 @@ const LoginPage = () => { navigate("/auth/login-otp"); } }, [IsLoginWithOTP]); + return ( - -

      Welcome to PMS!

      -

      - {IsLoginWithOTP - ? "Enter your email to receive a one-time password (OTP)." - : "Please sign-in to your account and start the adventure."} -

      -
      -
      - - - {errors.username && ( -
      - {errors.username.message} -
      - )} -
      +
      +
      +

      Welcome to PMS!

      +

      + {IsLoginWithOTP + ? "Enter your email to receive a one-time password (OTP)." + : "Please sign in to your account and start the adventure"} +

      - {!IsLoginWithOTP && ( - <> -
      - -
      - - + + {/* Email */} +
      + + + {errors.username && ( +
      + {errors.username.message}
      - {errors.password && ( -
      - {errors.password.message} -
      - )} -
      + )} +
      - -
      -
      - - -
      - Forgot Password? -
      - - )} - -
      - - {!IsLoginWithOTP &&
      OR
      } + {/* Password */} {!IsLoginWithOTP && ( - - )} -
      - + <> +
      + +
      + + setHidepass(!hidepass)} + > + + +
      + {errors.password && ( +
      + {errors.password.message} +
      + )} +
      -

      - New on our platform? - {IsLoginWithOTP ? ( - setLoginWithOtp(false)} + {/* Remember Me + Forgot Password */} +

      + + )} + + {/* Submit */} + + + {/* Login With OTP Button */} + {!IsLoginWithOTP && ( + <> +
      +
      or
      +
      + + + )} + + + {/* Footer Text */} + {!IsLoginWithOTP ? ( +

      + New on our platform? + + Request a Demo + +

      ) : ( - - Request a Demo - +
      + +
      )} -

      - +
      +
      ); }; -export default LoginPage; +export default LoginPage; \ No newline at end of file diff --git a/src/pages/authentication/LoginWithOtp.jsx b/src/pages/authentication/LoginWithOtp.jsx index 2157b4e1..8b07f8fb 100644 --- a/src/pages/authentication/LoginWithOtp.jsx +++ b/src/pages/authentication/LoginWithOtp.jsx @@ -52,7 +52,7 @@ const LoginWithOtp = () => { setLoading(false); localStorage.removeItem("otpUsername"); localStorage.removeItem("otpSentTime"); - navigate("/dashboard"); + navigate("/dashboard"); } catch (err) { showToast("Invalid or expired OTP.", "error"); @@ -123,8 +123,9 @@ const LoginWithOtp = () => { return ( - -
      + // +
      +

      Verify Your OTP

      Please enter the 4-digit code sent to your email.

      @@ -209,8 +210,9 @@ const LoginWithOtp = () => { )} +
      -
      + // ); }; diff --git a/src/pages/authentication/MainForgetPage.jsx b/src/pages/authentication/MainForgetPage.jsx new file mode 100644 index 00000000..caae1016 --- /dev/null +++ b/src/pages/authentication/MainForgetPage.jsx @@ -0,0 +1,26 @@ +import React from "react"; +// import LoginPage from "./LoginPage"; +import ForgotPasswordPage from "./ForgotPasswordPage"; + +const MainForgetPage = () => { + return ( + <> +
      +
      +
      + Login image +
      +
      + +
      + + ); +}; +export default MainForgetPage; diff --git a/src/pages/authentication/MainLogin.jsx b/src/pages/authentication/MainLogin.jsx new file mode 100644 index 00000000..03575f40 --- /dev/null +++ b/src/pages/authentication/MainLogin.jsx @@ -0,0 +1,24 @@ +import React from "react"; +import LoginPage from "./LoginPage"; +const MainLogin = () => { + return ( + <> +
      +
      +
      + Login image +
      +
      + +
      + + ); +}; +export default MainLogin; diff --git a/src/pages/authentication/MainLoginWithOTPPage.jsx b/src/pages/authentication/MainLoginWithOTPPage.jsx new file mode 100644 index 00000000..53b9fec7 --- /dev/null +++ b/src/pages/authentication/MainLoginWithOTPPage.jsx @@ -0,0 +1,26 @@ +import React from 'react' +import LoginWithOtp from './LoginWithOtp' + +const MainLoginWithOTPPage = () => { + return ( + <> +
      +
      +
      + Login image +
      +
      + +
      + + ) +} + +export default MainLoginWithOTPPage \ No newline at end of file diff --git a/src/pages/authentication/MainRegisterPage.jsx b/src/pages/authentication/MainRegisterPage.jsx new file mode 100644 index 00000000..a2a1a5ca --- /dev/null +++ b/src/pages/authentication/MainRegisterPage.jsx @@ -0,0 +1,25 @@ +import React from "react"; +import RegisterPage from "./RegisterPage"; + +const MainRegisterPage = () => { + return ( + <> +
      +
      +
      + Login image +
      +
      + +
      + + ); +}; +export default MainRegisterPage; diff --git a/src/pages/authentication/MainResetPasswordPage.jsx b/src/pages/authentication/MainResetPasswordPage.jsx new file mode 100644 index 00000000..36fd71e6 --- /dev/null +++ b/src/pages/authentication/MainResetPasswordPage.jsx @@ -0,0 +1,26 @@ +import React from 'react' +import ResetPasswordPage from './ResetPassword' + +const MainResetPasswordPage = () => { + return ( + <> +
      +
      +
      + Login image +
      +
      + +
      + + ) +} + +export default MainResetPasswordPage \ No newline at end of file diff --git a/src/pages/authentication/RegisterPage.jsx b/src/pages/authentication/RegisterPage.jsx index 16517816..65b7d619 100644 --- a/src/pages/authentication/RegisterPage.jsx +++ b/src/pages/authentication/RegisterPage.jsx @@ -37,28 +37,33 @@ const registerSchema = z.object({ const RegisterPage = () => { const [registered, setRegristered] = useState(false); const [industries, setIndustries] = useState([]); + const [Loading,setLoading] = useState(false) const { register, handleSubmit, - formState: { errors }, + formState: { errors },reset } = useForm({ resolver: zodResolver(registerSchema), }); const onSubmit = async (data) => { try { + setLoading(true) const response = await MarketRepository.requestDemo(data); - showToast("Your Registration SuccessFully !"); + showToast("Your request has been sent successfully. Please stay in touch!"); setRegristered(true); + setLoading(false) + reset() } catch (error) { showToast(error.message, "error"); + setLoading(false) } }; useEffect(() => { fetchIndustries(); }, []); - useEffect(() => {}, [industries]); + useEffect(() => { }, [industries]); const fetchIndustries = async () => { try { @@ -71,23 +76,27 @@ const RegisterPage = () => { }; return ( <> - {!registered && ( - -

      Adventure starts here 🚀

      + +
      +
      + +

      Adventure starts here

      Make your app management easy and fun!

      -
      + +
      +
      {
      )}
      -
      +
      {
      )}
      -
      +
      +
      -
      -
      {errors.contactPerson && (
      {
      )}
      -
      +
      -
      -
      {errors.contactNumber && (
      {
      )}
      -
      +
      -
      -
      {errors.about && (
      {
      )}
      -
      +
      -
      -
      {errors.oragnizationSize && (
      {
      )}
      -
      +
      -
      -
      {errors.industryId && (
      {
      )}
      -
      +
      { {...register("terms")} /> +
      {errors.terms && (
      { )}

      - Already have an account? + Already have an account? - + Back to login

      - - )} - {registered && ( - -
      Thank you for contacting us
      -

      We will get back to you soon

      - - - Back to login - -
      - )} +
      +
      ); }; -export default RegisterPage; +export default RegisterPage; \ No newline at end of file diff --git a/src/pages/authentication/ResetPasswordPage.jsx b/src/pages/authentication/ResetPassword.jsx similarity index 94% rename from src/pages/authentication/ResetPasswordPage.jsx rename to src/pages/authentication/ResetPassword.jsx index 21b03df0..9c7ab0d2 100644 --- a/src/pages/authentication/ResetPasswordPage.jsx +++ b/src/pages/authentication/ResetPassword.jsx @@ -33,7 +33,7 @@ const resetPasswordSchema = z path: ["confirmPassword"], }); -const ResetPasswordPage = () => { +const ResetPassword = () => { const [searchParams] = useSearchParams(); const [loading, setLoading] = useState(false); const [hidepass, setHidepass] = useState(true); @@ -67,7 +67,6 @@ const ResetPasswordPage = () => { navigate("/auth/login", { replace: true }); // setLoading(false); } catch (error) { - debugger; setLoading(false); if (error?.response?.status === 400) { showToast("Please check valid Credentials", "error"); @@ -94,7 +93,8 @@ const ResetPasswordPage = () => { ); } return ( - +
      +

      Reset Password? 🔒

      Enter your email and new password to update.

      { className="mb-3" onSubmit={handleSubmit(onSubmitResetPassword)} > -
      +
      @@ -124,9 +124,9 @@ const ResetPasswordPage = () => { )}
      -
      +
      -
      @@ -238,8 +238,9 @@ const ResetPasswordPage = () => { Back to login
      - +
      +
      ); }; -export default ResetPasswordPage; +export default ResetPassword; diff --git a/src/pages/authentication/page-auth.css b/src/pages/authentication/page-auth.css index 86ceb214..8492495b 100644 --- a/src/pages/authentication/page-auth.css +++ b/src/pages/authentication/page-auth.css @@ -18,6 +18,7 @@ } .authentication-wrapper.authentication-cover .authentication-inner { height: 100vh; + background-color: #fff; } .authentication-wrapper.authentication-basic .authentication-inner { max-width: 400px; diff --git a/src/pages/employee/EmployeeList.jsx b/src/pages/employee/EmployeeList.jsx index 5cd7ab2d..ca58f018 100644 --- a/src/pages/employee/EmployeeList.jsx +++ b/src/pages/employee/EmployeeList.jsx @@ -79,11 +79,11 @@ const EmployeeList = () => { } ); - useEffect(() => { - if (selectedProjectId === null) { - dispatch(setProjectId(projectNames[0]?.id)); - } - }, [selectedProjectId]); +useEffect(() => { + if (!selectedProjectId && projectNames?.length > 0) { + dispatch(setProjectId(projectNames[0].id)); + } +}, [selectedProjectId, projectNames, dispatch]); const navigate = useNavigate(); const applySearchFilter = (data, text) => { @@ -177,10 +177,12 @@ const EmployeeList = () => { useEffect(() => { if (!loading && Array.isArray(employees)) { const sorted = [...employees].sort((a, b) => { - const nameA = `${a.firstName || ""}${a.middleName || ""}${a.lastName || "" - }`.toLowerCase(); - const nameB = `${b.firstName || ""}${b.middleName || ""}${b.lastName || "" - }`.toLowerCase(); + const nameA = `${a.firstName || ""}${a.middleName || ""}${ + a.lastName || "" + }`.toLowerCase(); + const nameB = `${b.firstName || ""}${b.middleName || ""}${ + b.lastName || "" + }`.toLowerCase(); return nameA?.localeCompare(nameB); }); @@ -278,8 +280,9 @@ const EmployeeList = () => { ? "Suspend Employee" : "Reactivate Employee" } - message={`Are you sure you want to ${selectedEmpFordelete?.isActive ? "suspend" : "reactivate" - } this employee?`} + message={`Are you sure you want to ${ + selectedEmpFordelete?.isActive ? "suspend" : "reactivate" + } this employee?`} onSubmit={() => suspendEmployee({ employeeId: selectedEmpFordelete.id, @@ -511,8 +514,9 @@ const EmployeeList = () => { Status { )} {/* Conditional messages for no data or no search results */} {!loading && - displayData?.length === 0 && - searchText && - !showAllEmployees ? ( + displayData?.length === 0 && + searchText && + !showAllEmployees ? ( @@ -544,14 +548,14 @@ const EmployeeList = () => { ) : null} {!loading && - displayData?.length === 0 && - (!searchText || showAllEmployees) ? ( + displayData?.length === 0 && + (!searchText || showAllEmployees) ? ( - No Data Found + No team members assigned yet ) : null} @@ -570,7 +574,9 @@ const EmployeeList = () => {
      - navigate(`/employee/${item.id}`) + navigate( + `/employee/${item.id}?for=attendance` + ) } className="text-heading text-truncate cursor-pointer" > @@ -606,9 +612,10 @@ const EmployeeList = () => { {item.jobRole || "Not Assign Yet"} - - {moment(item.joiningDate)?.format("DD-MMM-YYYY")} + {item.joiningDate + ? moment(item.joiningDate).format("DD-MMM-YYYY") + : "NA"} {showInactive ? ( @@ -637,56 +644,47 @@ const EmployeeList = () => {
      - {/* View always visible */} - - {/* If ACTIVE employee */} - {item.isActive && ( + + {!item.isSystem && ( <> - - {/* Suspend only when active */} - {item.isActive && ( - - )} - - )} - - {/* If INACTIVE employee AND inactive toggle is ON */} - {!item.isActive && showInactive && ( - - )}
      @@ -703,8 +701,9 @@ const EmployeeList = () => {
      -
      -
      -
      +
      +
      + +
      +
      +
      setSearchTerm(e.target.value)} + />
      + {hasMasterPermission && ( + + )}
      - - -
      + +
      -
      ); diff --git a/src/pages/master/MasterTable.jsx b/src/pages/master/MasterTable.jsx index bc7c10c0..3f3297b5 100644 --- a/src/pages/master/MasterTable.jsx +++ b/src/pages/master/MasterTable.jsx @@ -9,7 +9,7 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => { const selectedMaster = useSelector( (store) => store.localVariables.selectedMaster ); - const hiddenColumns = [ + const hiddenColumns = [ "id", "featurePermission", "tenant", @@ -20,7 +20,14 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => { "noOfPersonsRequired", "color", "displayName", - "permissionIds" + "permissionIds", + "entityTypeId", + "regexExpression", + "isMandatory", + "maxFilesAllowed", + "maxSizeAllowedInMB", + "isValidationRequired", + "documentCategory", ]; const safeData = Array.isArray(data) ? data : []; @@ -64,28 +71,35 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => { : col.label, })); - const handleSystemDefined = (message) =>{ - if(message){ - showToast(`The system-defined item ${selectedMaster} cannot be ${message}.`) - } + const handleSystemDefined = (message) => { + if (message) { + showToast( + `The system-defined item ${selectedMaster} cannot be ${message}.` + ); } + }; return (
      {loading ? (

      Loading...

      ) : ( - - +
      + - - + + @@ -120,28 +134,28 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => { ))}
      {selectedMaster === "Activity" ? "Activity" : "Name"} {selectedMaster === "Activity" ? "Unit" : "Description"} + {" "} + {selectedMaster === "Activity" ? "Activity" : "Name"} + + {" "} + {selectedMaster === "Activity" + ? "Unit" + : selectedMaster === "Document Type" + ? "Content Type" + : "Description"} + Actions - {(selectedMaster === "Application Role" || selectedMaster === "Work Category") && item?.isSystem ? ( + {(selectedMaster === "Application Role" || + selectedMaster === "Work Category") && + item?.isSystem ? ( <> - + - - + + ) : ( <> diff --git a/src/pages/project/ProjectDetails.jsx b/src/pages/project/ProjectDetails.jsx index 1df27bb9..c7127837 100644 --- a/src/pages/project/ProjectDetails.jsx +++ b/src/pages/project/ProjectDetails.jsx @@ -16,9 +16,7 @@ import { useSelectedProject, } from "../../slices/apiDataManager"; import "./ProjectDetails.css"; -import { - useProjectDetails, -} from "../../hooks/useProjects"; +import { useProjectDetails } from "../../hooks/useProjects"; import { ComingSoonPage } from "../Misc/ComingSoonPage"; import Directory from "../Directory/Directory"; import eventBus from "../../services/eventBus"; @@ -26,19 +24,22 @@ import ProjectProgressChart from "../../components/Dashboard/ProjectProgressChar import { useProjectName } from "../../hooks/useProjects"; import AttendanceOverview from "../../components/Dashboard/AttendanceChart"; import { setProjectId } from "../../slices/localVariablesSlice"; +import ProjectDocument from "../../components/Project/ProjectDocuments"; +import ProjectDocuments from "../../components/Project/ProjectDocuments"; +import ProjectSetting from "../../components/Project/ProjectSetting"; const ProjectDetails = () => { const projectId = useSelectedProject() const { projectNames, fetchData } = useProjectName(); - const dispatch = useDispatch() + const dispatch = useDispatch(); useEffect(() => { if (projectId == null) { dispatch(setProjectId(projectNames[0]?.id)); } - }, [projectNames]) + }, [projectNames]); const { projects_Details, @@ -49,12 +50,15 @@ const ProjectDetails = () => { // const [activePill, setActivePill] = useState("profile"); const [activePill, setActivePill] = useState(() => { - return localStorage.getItem("lastActiveProjectTab") || "profile"; -}); + return localStorage.getItem("lastActiveProjectTab") || "profile"; + }); const handler = useCallback( (msg) => { - if (msg.keyword === "Update_Project" && projects_Details?.id === msg.response.id) { + if ( + msg.keyword === "Update_Project" && + projects_Details?.id === msg.response.id + ) { refetch(); } }, @@ -66,11 +70,10 @@ const ProjectDetails = () => { return () => eventBus.off("project", handler); }, [handler]); - const handlePillClick = (pillKey) => { - setActivePill(pillKey); - localStorage.setItem("lastActiveProjectTab", pillKey); // ✅ Save to localStorage -}; - + const handlePillClick = (pillKey) => { + setActivePill(pillKey); + localStorage.setItem("lastActiveProjectTab", pillKey); // ✅ Save to localStorage + }; const renderContent = () => { if (projectLoading || !projects_Details) return ; @@ -80,14 +83,19 @@ const ProjectDetails = () => { return ( <>
      -
      +
      - -
      - + +
      + {" "} + +
      @@ -103,14 +111,10 @@ const ProjectDetails = () => { ); case "infra": - return ( - - ); + return ; case "workplan": - return ( - - ); + return ; case "directory": return ( @@ -118,6 +122,18 @@ const ProjectDetails = () => {
      ); + case "documents": + return ( +
      + +
      + ); + case "setting": + return ( +
      + +
      + ); default: return ; @@ -142,4 +158,4 @@ const ProjectDetails = () => { ); }; -export default ProjectDetails; \ No newline at end of file +export default ProjectDetails; diff --git a/src/repositories/DocumentRepository.jsx b/src/repositories/DocumentRepository.jsx new file mode 100644 index 00000000..0f9376dd --- /dev/null +++ b/src/repositories/DocumentRepository.jsx @@ -0,0 +1,26 @@ +import { api } from "../utils/axiosClient"; + +export const DocumentRepository = { + uploadDocument:(data)=> api.post(`/api/Document/upload`,data), + getDocumentList:(entityTypeId,entityId,pageSize, pageNumber, filter,searchString,isActive)=>{ + const payloadJsonString = JSON.stringify(filter); + return api.get(`/api/Document/list/${entityTypeId}/entity/${entityId}/?pageSize=${pageSize}&pageNumber=${pageNumber}&filter=${payloadJsonString}&searchString=${searchString}&isActive=${isActive}`) + }, + getDocumentById:(id)=>api.get(`/api/Document/get/details/${id}`), + + getFilterEntities:(entityTypeId)=>api.get(`/api/Document/get/filter/${entityTypeId}`), + + UpdateDocument:(documentId,data)=>api.put(`/api/Document/edit/${documentId}`,data), + + getDocumentVersionList:(parentAttachmentId,pageSize,pageNumber)=>api.get(`/api/Document/list/versions/${parentAttachmentId}/?pageSize=${pageSize}&pageNumber=${pageNumber}`), + + getDocumentVersion:(id)=>api.get(`/api/Document/get/version/${id}`), + + verifyDocument:(id,isVerify)=>api.post(`/api/Document/verify/${id}/?isVerify=${isVerify}`), + + deleteDocument:(id,isActive)=>api.delete(`/api/Document/delete/${id}/?isActive=${isActive}`), + + getDocumentTags:()=>api.get('/api/Document/get/tags') + + +} \ No newline at end of file diff --git a/src/repositories/MastersRepository.jsx b/src/repositories/MastersRepository.jsx index cfb9a890..a853fdbe 100644 --- a/src/repositories/MastersRepository.jsx +++ b/src/repositories/MastersRepository.jsx @@ -18,7 +18,7 @@ export const RolesRepository = { }; export const MasterRespository = { - getMasterMenus:()=>api.get("/api/AppMenu/get/master-list"), + getMasterMenus: () => api.get("/api/AppMenu/get/master-list"), getRoles: () => api.get("/api/roles"), createRole: (data) => api.post("/api/roles", data), @@ -48,6 +48,9 @@ export const MasterRespository = { api.delete(`/api/Master/payment-mode/delete/${id}`, (isActive = false)), "Expense Status": (id, isActive) => api.delete(`/api/Master/expenses-status/delete/${id}`, (isActive = false)), + "Document Type": (id) => api.delete(`/api/Master/document-type/delete/${id}`), + "Document Category": (id) => + api.delete(`/api/Master/document-category/delete/${id}`), getWorkCategory: () => api.get(`/api/master/work-categories`), createWorkCategory: (data) => api.post(`/api/master/work-category`, data), @@ -81,4 +84,26 @@ export const MasterRespository = { createExpenseStatus: (data) => api.post("/api/Master/expenses-status", data), updateExepnseStatus: (id, data) => api.put(`/api/Master/expenses-status/edit/${id}`, data), + + getDocumentCategories: (entityType) => + api.get( + `/api/Master/document-category/list${ + entityType ? `?entityTypeId=${entityType}` : "" + }` + ), + createDocumenyCategory: (data) => + api.post(`/api/Master/document-category`, data), + updateDocumentCategory: (id, data) => + api.put(`/api/Master/document-category/edit/${id}`, data), + + getDocumentTypes: (category) => + api.get( + `/api/Master/document-type/list${ + category ? `?documentCategoryId=${category}` : "" + }` + ), + + createDocumentType: (data) => api.post(`/api/Master/document-type`, data), + updateDocumentType: (id, data) => + api.put(`/api/Master/document-type/edit/${id}`, data), }; diff --git a/src/repositories/ProjectRepository.jsx b/src/repositories/ProjectRepository.jsx index b2f0f7ff..6543301a 100644 --- a/src/repositories/ProjectRepository.jsx +++ b/src/repositories/ProjectRepository.jsx @@ -37,6 +37,14 @@ const ProjectRepository = { api.get( `/api/project/tasks-employee/${id}?fromDate=${fromDate}&toDate=${toDate}` ), + + + // Permission Managment for Employee at Project Level + + getProjectLevelEmployeeList:(projectId)=>api.get(`/api/Project/get/proejct-level/employees/${projectId}`), + getProjectLevelModules:()=>api.get(`/api/Project/get/proejct-level/modules`), + getProjectLevelEmployeePermissions:(employeeId,projectId)=>api.get(`/api/Project/get/project-level-permission/employee/${employeeId}/project/${projectId}`), + updateProjectLevelEmployeePermission:(data)=>api.post(`/api/Project/assign/project-level-permission`,data) }; export const TasksRepository = { diff --git a/src/router/AppRoutes.jsx b/src/router/AppRoutes.jsx index 019a3e8d..5e71c0b6 100644 --- a/src/router/AppRoutes.jsx +++ b/src/router/AppRoutes.jsx @@ -1,4 +1,3 @@ -// AppRoutes.jsx import React from "react"; import { createBrowserRouter, RouterProvider, Outlet } from "react-router-dom"; @@ -10,7 +9,6 @@ import HomeLayout from "../layouts/HomeLayout"; import LoginPage from "../pages/authentication/LoginPage"; import RegisterPage from "../pages/authentication/RegisterPage"; import ForgotPasswordPage from "../pages/authentication/ForgotPasswordPage"; -import ResetPasswordPage from "../pages/authentication/ResetPasswordPage"; import ChangePasswordPage from "../pages/authentication/ChangePassword"; // Home & Protected Pages @@ -38,23 +36,33 @@ import LegalInfoCard from "../pages/TermsAndConditions/LegalInfoCard"; import ProtectedRoute from "./ProtectedRoute"; import Directory from "../pages/Directory/Directory"; import LoginWithOtp from "../pages/authentication/LoginWithOtp"; -import TenantPage from "../pages/Tenant/TenantPage"; -import CreateTenant from "../pages/Tenant/CreateTenant"; import ExpensePage from "../pages/Expense/ExpensePage"; -import TenantDetails from "../pages/Tenant/TenantDetails"; -import SelfTenantDetails from "../pages/Tenant/SelfTenantDetails"; +import LandingPage from "../pages/Home/LandingPage"; +import MainLogin from "../pages/authentication/MainLogin"; +import MainLoginWithOTPPage from "../pages/authentication/MainLoginWithOTPPage"; +import MainRegisterPage from "../pages/authentication/MainRegisterPage"; +import MainForgetPage from "../pages/authentication/MainForgetPage"; +import MainResetPasswordPage from "../pages/authentication/MainResetPasswordPage"; +import TenantPage from "../pages/Tenant/TenantPage"; +import { Navigate } from "react-router-dom"; +import RootRedirect from "./RootRedirect"; +import CreateTenant from "../pages/Tenant/CreateTenant"; import SuperTenantDetails from "../pages/Tenant/SuperTenantDetails"; - +import SelfTenantDetails from "../pages/Tenant/SelfTenantDetails"; const router = createBrowserRouter( [ + { + path: "/", + element: , + }, { element: , children: [ - { path: "/auth/login", element: }, - { path: "/auth/login-otp", element: }, - { path: "/market/enquire", element: }, - { path: "/auth/forgot-password", element: }, - { path: "/reset-password", element: }, + { path: "/auth/login", element: }, + { path: "/auth/login-otp", element: }, + { path: "/auth/reqest/demo", element: }, + { path: "/auth/forgot-password", element: }, + { path: "/reset-password", element: }, { path: "/legal-info", element: }, { path: "/auth/changepassword", element: }, ], @@ -66,15 +74,12 @@ const router = createBrowserRouter( { element: , children: [ - { path: "/", element: }, { path: "/dashboard", element: }, { path: "/projects", element: }, { path: "/projects/details", element: }, { path: "/project/manage/:projectId", element: }, { path: "/employees", element: }, { path: "/employee/:employeeId", element: }, - // { path: "/employee/manage", element: }, - // {path: "/employee/manage/:employeeId", element: }, { path: "/directory", element: }, { path: "/inventory", element: }, { path: "/activities/attendance", element: }, @@ -101,7 +106,6 @@ const router = createBrowserRouter( }, ], { - // ✅ Enables the v7 splat path resolution behavior future: { v7_relativeSplatPath: true, v7_startTransition: true, diff --git a/src/router/RootRedirect.jsx b/src/router/RootRedirect.jsx new file mode 100644 index 00000000..d00f99fe --- /dev/null +++ b/src/router/RootRedirect.jsx @@ -0,0 +1,13 @@ +import React from "react"; +import { Navigate } from "react-router-dom"; + +const RootRedirect = () => { + const isAuthenticated = !!localStorage.getItem("jwtToken"); + return isAuthenticated ? ( + + ) : ( + + ); +}; + +export default RootRedirect; diff --git a/src/slices/apiDataManager.jsx b/src/slices/apiDataManager.jsx index 97f6dcb5..ad4d38a1 100644 --- a/src/slices/apiDataManager.jsx +++ b/src/slices/apiDataManager.jsx @@ -4,10 +4,9 @@ import { clearApiCacheKey, flushApiCache, } from "../slices/apiCacheSlice"; -import {setLoginUserPermmisions} from "./globalVariablesSlice"; +import { setLoginUserPermmisions } from "./globalVariablesSlice"; import { useSelector } from "react-redux"; - // Cache data export const cacheData = (key, data) => { store.dispatch(cacheApiResponse({ key, data })); @@ -28,9 +27,7 @@ export const clearAllCache = () => { store.dispatch(flushApiCache()); }; - - -export const cacheProfileData = ( data) => { +export const cacheProfileData = (data) => { store.dispatch(setLoginUserPermmisions(data)); }; // Get cached data @@ -39,14 +36,20 @@ export const getCachedProfileData = () => { }; export const useSelectedProject = () => { - const selectedProject = useSelector((store)=> store.localVariables.projectId); - var project = localStorage.getItem("project"); - if(project){ - return project - } else{ - return selectedProject + const selectedProject = useSelector( + (store) => store.localVariables.projectId + ); + + const project = localStorage.getItem("project"); + + if (project) { + try { + const parsed = JSON.parse(project); + return parsed ?? selectedProject; + } catch (e) { + return selectedProject; + } } - - - -}; \ No newline at end of file + + return selectedProject; +} \ No newline at end of file diff --git a/src/slices/localVariablesSlice.jsx b/src/slices/localVariablesSlice.jsx index 7c996608..0b0a8405 100644 --- a/src/slices/localVariablesSlice.jsx +++ b/src/slices/localVariablesSlice.jsx @@ -23,7 +23,7 @@ const localVariablesSlice = createSlice({ setProjectId: (state, action) => { localStorage.setItem("project",null) state.projectId = action.payload; - localStorage.setItem("project",state.projectId) + localStorage.setItem("project",state.projectId || null) }, refreshData: ( state, action ) => { diff --git a/src/utils/FileIcon.jsx b/src/utils/FileIcon.jsx new file mode 100644 index 00000000..67088713 --- /dev/null +++ b/src/utils/FileIcon.jsx @@ -0,0 +1,26 @@ +const contentTypeIcons = { + "application/pdf": "fa-solid fa-file-pdf text-danger", + "application/msword": "fa-solid fa-file-word text-primary", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document": + "fa-solid fa-file-word text-primary", + "application/vnd.ms-excel": "fa-solid fa-file-excel text-success", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": + "fa-solid fa-file-excel text-success", + "application/vnd.ms-powerpoint": "fa-solid fa-file-powerpoint text-warning", + "application/vnd.openxmlformats-officedocument.presentationml.presentation": + "fa-solid fa-file-powerpoint text-warning", + "image/jpg": "fa-solid fa-file-image text-info", + "image/jpeg": "fa-solid fa-file-image text-info", + "image/png": "fa-solid fa-file-image text-info", + "image/gif": "fa-solid fa-file-image text-info", + "text/plain": "fa-solid fa-file-lines text-secondary", + "text/csv": "fa-solid fa-file-csv text-success", + "application/json": "fa-solid fa-file-code text-dark", + folder: "fa-solid fa-folder text-warning", // special for folders + default: "fa-solid fa-file text-muted", +}; + +export const FileIcon = ({ type, size = "fs-4", className = "" }) => { + const iconClass = contentTypeIcons[type] || contentTypeIcons.default; + return ; +}; \ No newline at end of file diff --git a/src/utils/appUtils.js b/src/utils/appUtils.js index 17686ced..b6b3a8aa 100644 --- a/src/utils/appUtils.js +++ b/src/utils/appUtils.js @@ -61,3 +61,11 @@ export const getIconByFileType = (type = "") => { return "bx bx-file"; }; + + +export const normalizeAllowedContentTypes = (allowedContentType) => { + if (!allowedContentType) return []; + if (Array.isArray(allowedContentType)) return allowedContentType; + if (typeof allowedContentType === "string") return allowedContentType.split(","); + return []; +}; \ No newline at end of file diff --git a/src/utils/constants.jsx b/src/utils/constants.jsx index 555e3a0b..ab66b2c1 100644 --- a/src/utils/constants.jsx +++ b/src/utils/constants.jsx @@ -1,7 +1,7 @@ export const THRESH_HOLD = 48; // hours export const DURATION_TIME = 10; // minutes export const ITEMS_PER_PAGE = 20; -export const OTP_EXPIRY_SECONDS = 600 // OTP time +export const OTP_EXPIRY_SECONDS = 300 // OTP time export const MANAGE_MASTER = "588a8824-f924-4955-82d8-fc51956cf323"; @@ -39,12 +39,14 @@ export const VIEW_TASK = "9fcc5f87-25e3-4846-90ac-67a71ab92e3c" export const ASSIGN_REPORT_TASK = "6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2" +// ------------------------Directory------------------------------------- export const DIRECTORY_ADMIN = "4286a13b-bb40-4879-8c6d-18e9e393beda" export const DIRECTORY_MANAGER = "62668630-13ce-4f52-a0f0-db38af2230c5" export const DIRECTORY_USER = "0f919170-92d4-4337-abd3-49b66fc871bb" +// -----------------------Expense---------------------------------------- export const VIEW_SELF_EXPENSE = "385be49f-8fde-440e-bdbc-3dffeb8dd116" export const VIEW_ALL_EXPNESE = "01e06444-9ca7-4df4-b900-8c3fa051b92f"; @@ -55,7 +57,6 @@ export const REVIEW_EXPENSE = "1f4bda08-1873-449a-bb66-3e8222bd871b"; export const APPROVE_EXPENSE = "eaafdd76-8aac-45f9-a530-315589c6deca"; - export const PROCESS_EXPENSE = "ea5a1529-4ee8-4828-80ea-0e23c9d4dd11" export const EXPENSE_MANAGE = "ea5a1529-4ee8-4828-80ea-0e23c9d4dd11" @@ -64,10 +65,19 @@ export const EXPENSE_REJECTEDBY = ["d1ee5eec-24b6-4364-8673-a8f859c60729","965ed export const EXPENSE_DRAFT = "297e0d8f-f668-41b5-bfea-e03b354251c8" +// ----------------------------Tenant------------------------- export const SUPPER_TENANT = "d032cb1a-3f30-462c-bef0-7ace73a71c0b" export const MANAGE_TENANTS = "00e20637-ce8d-4417-bec4-9b31b5e65092" export const VIEW_TENANTS = "647145c6-2108-4c98-aab4-178602236e55" export const ActiveTenant = "297e0d8f-f668-41b5-bfea-e03b354251c8" + +// ---------------------Documents--------------------------------- +export const VIEW_DOCUMENT = "71189504-f1c8-4ca5-8db6-810497be2854"; +export const UPLOAD_DOCUMENT = "3f6d1f67-6fa5-4b7c-b17b-018d4fe4aab8"; +export const MODIFY_DOCUMENT = "c423fd81-6273-4b9d-bb5e-76a0fb343833"; +export const DELETE_DOCUMENT = "40863a13-5a66-469d-9b48-135bc5dbf486"; +export const DOWNLOAD_DOCUMENT = "404373d0-860f-490e-a575-1c086ffbce1d"; +export const VERIFY_DOCUMENT = "13a1f30f-38d1-41bf-8e7a-b75189aab8e0"; // -------------------Application Role------------------------------ // 1 - Expense Manage @@ -79,6 +89,12 @@ export const TENANT_STATUS = [ {id:"35d7840a-164a-448b-95e6-efb2ec84a751",name:"Supspended"} ] +export const DOCUMENTS_ENTITIES = { + ProjectEntity : "c8fe7115-aa27-43bc-99f4-7b05fabe436e", + EmployeeEntity:"dbb9555a-7a0c-40f2-a9ed-f0463f1ceed7", +} + + export const CONSTANT_TEXT = { }