diff --git a/package.json b/package.json index ffd57b6..3c6caad 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "@radix-ui/react-toggle-group": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.4", "@tailwindcss/typography": "^0.5.15", - "@tanstack/react-query": "^5.62.0", + "@tanstack/react-query": "^5.62.1", "@tanstack/react-table": "^8.20.5", "@tiptap/core": "^2.10.3", "@tiptap/extension-link": "^2.10.3", @@ -70,7 +70,7 @@ "react-hook-form": "^7.53.2", "react-image-crop": "^11.0.7", "react-medium-image-zoom": "^5.2.11", - "recharts": "^2.13.3", + "recharts": "^2.14.0", "sonner": "^1.7.0", "tailwind-merge": "^2.5.5", "tailwindcss-animate": "^1.0.7", @@ -84,8 +84,8 @@ "@types/node": "^22.10.1", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", - "@typescript-eslint/eslint-plugin": "^8.16.0", - "@typescript-eslint/parser": "^8.16.0", + "@typescript-eslint/eslint-plugin": "^8.17.0", + "@typescript-eslint/parser": "^8.17.0", "eslint": "^9.16.0", "eslint-config-next": "^14.2.18", "eslint-plugin-react": "^7.37.2", @@ -98,7 +98,7 @@ "qs": "^6.13.1", "tailwindcss": "^3.4.15", "typescript": "^5.7.2", - "typescript-eslint": "^8.16.0" + "typescript-eslint": "^8.17.0" }, "packageManager": "pnpm@9.6.0+sha512.38dc6fba8dba35b39340b9700112c2fe1e12f10b17134715a4aa98ccf7bb035e76fd981cf0bb384dfa98f8d6af5481c2bef2f4266a24bfa20c34eb7147ce0b5e" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c97cfa7..ddcf98c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -95,8 +95,8 @@ importers: specifier: ^0.5.15 version: 0.5.15(tailwindcss@3.4.15) "@tanstack/react-query": - specifier: ^5.62.0 - version: 5.62.0(react@18.3.1) + specifier: ^5.62.1 + version: 5.62.1(react@18.3.1) "@tanstack/react-table": specifier: ^8.20.5 version: 8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -191,8 +191,8 @@ importers: specifier: ^5.2.11 version: 5.2.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) recharts: - specifier: ^2.13.3 - version: 2.13.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^2.14.0 + version: 2.14.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) sonner: specifier: ^1.7.0 version: 1.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -228,11 +228,11 @@ importers: specifier: ^18.3.1 version: 18.3.1 "@typescript-eslint/eslint-plugin": - specifier: ^8.16.0 - version: 8.16.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + specifier: ^8.17.0 + version: 8.17.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) "@typescript-eslint/parser": - specifier: ^8.16.0 - version: 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + specifier: ^8.17.0 + version: 8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) eslint: specifier: ^9.16.0 version: 9.16.0(jiti@1.21.6) @@ -250,7 +250,7 @@ importers: version: 12.1.1(eslint@9.16.0(jiti@1.21.6)) eslint-plugin-unused-imports: specifier: ^4.1.4 - version: 4.1.4(@typescript-eslint/eslint-plugin@8.16.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6)) + version: 4.1.4(@typescript-eslint/eslint-plugin@8.17.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6)) globals: specifier: ^15.13.0 version: 15.13.0 @@ -270,8 +270,8 @@ importers: specifier: ^5.7.2 version: 5.7.2 typescript-eslint: - specifier: ^8.16.0 - version: 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + specifier: ^8.17.0 + version: 8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) packages: "@alloc/quick-lru@5.2.0": @@ -1519,16 +1519,16 @@ packages: peerDependencies: tailwindcss: ">=3.0.0 || insiders || >=4.0.0-alpha.20" - "@tanstack/query-core@5.62.0": + "@tanstack/query-core@5.62.1": resolution: { - integrity: sha512-sx38bGrqF9bop92AXOvzDr0L9fWDas5zXdPglxa9cuqeVSWS7lY6OnVyl/oodfXjgOGRk79IfCpgVmxrbHuFHg==, + integrity: sha512-thYv90GkMcfumgmtp6sptC18SqxWwXTCKUuk7jyeHHn7kYouh0VJrowuuBffAIBiR3Z8OnsccmPUnP1leKJBVQ==, } - "@tanstack/react-query@5.62.0": + "@tanstack/react-query@5.62.1": resolution: { - integrity: sha512-tj2ltjAn2a3fs+Dqonlvs6GyLQ/LKVJE2DVSYW+8pJ3P6/VCVGrfqv5UEchmlP7tLOvvtZcOuSyI2ooVlR5Yqw==, + integrity: sha512-gb4eglrgW+yOeiNPkpqFyN8oLrFafHrHE+q2LzVl7TfyA4fuQluH92NTl6Jed7ae35v+BNtAQng9mykywWLzfA==, } peerDependencies: react: ^18 || ^19 @@ -1921,10 +1921,10 @@ packages: integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==, } - "@typescript-eslint/eslint-plugin@8.16.0": + "@typescript-eslint/eslint-plugin@8.17.0": resolution: { - integrity: sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q==, + integrity: sha512-HU1KAdW3Tt8zQkdvNoIijfWDMvdSweFYm4hWh+KwhPstv+sCmWb89hCIP8msFm9N1R/ooh9honpSuvqKWlYy3w==, } engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: @@ -1935,10 +1935,10 @@ packages: typescript: optional: true - "@typescript-eslint/parser@8.16.0": + "@typescript-eslint/parser@8.17.0": resolution: { - integrity: sha512-D7DbgGFtsqIPIFMPJwCad9Gfi/hC0PWErRRHFnaCWoEDYi5tQUDiJCTmGUbBiLzjqAck4KcXt9Ayj0CNlIrF+w==, + integrity: sha512-Drp39TXuUlD49F7ilHHCG7TTg8IkA+hxCuULdmzWYICxGXvDXmDmWEjJYZQYgf6l/TFfYNE167m7isnc3xlIEg==, } engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: @@ -1948,17 +1948,17 @@ packages: typescript: optional: true - "@typescript-eslint/scope-manager@8.16.0": + "@typescript-eslint/scope-manager@8.17.0": resolution: { - integrity: sha512-mwsZWubQvBki2t5565uxF0EYvG+FwdFb8bMtDuGQLdCCnGPrDEDvm1gtfynuKlnpzeBRqdFCkMf9jg1fnAK8sg==, + integrity: sha512-/ewp4XjvnxaREtqsZjF4Mfn078RD/9GmiEAtTeLQ7yFdKnqwTOgRMSvFz4et9U5RiJQ15WTGXPLj89zGusvxBg==, } engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - "@typescript-eslint/type-utils@8.16.0": + "@typescript-eslint/type-utils@8.17.0": resolution: { - integrity: sha512-IqZHGG+g1XCWX9NyqnI/0CX5LL8/18awQqmkZSl2ynn8F76j579dByc0jhfVSnSnhf7zv76mKBQv9HQFKvDCgg==, + integrity: sha512-q38llWJYPd63rRnJ6wY/ZQqIzPrBCkPdpIsaCfkR3Q4t3p6sb422zougfad4TFW9+ElIFLVDzWGiGAfbb/v2qw==, } engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: @@ -1968,17 +1968,17 @@ packages: typescript: optional: true - "@typescript-eslint/types@8.16.0": + "@typescript-eslint/types@8.17.0": resolution: { - integrity: sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ==, + integrity: sha512-gY2TVzeve3z6crqh2Ic7Cr+CAv6pfb0Egee7J5UAVWCpVvDI/F71wNfolIim4FE6hT15EbpZFVUj9j5i38jYXA==, } engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - "@typescript-eslint/typescript-estree@8.16.0": + "@typescript-eslint/typescript-estree@8.17.0": resolution: { - integrity: sha512-E2+9IzzXMc1iaBy9zmo+UYvluE3TW7bCGWSF41hVWUE01o8nzr1rvOQYSxelxr6StUvRcTMe633eY8mXASMaNw==, + integrity: sha512-JqkOopc1nRKZpX+opvKqnM3XUlM7LpFMD0lYxTqOTKQfCWAmxw45e3qlOCsEqEB2yuacujivudOFpCnqkBDNMw==, } engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: @@ -1987,10 +1987,10 @@ packages: typescript: optional: true - "@typescript-eslint/utils@8.16.0": + "@typescript-eslint/utils@8.17.0": resolution: { - integrity: sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA==, + integrity: sha512-bQC8BnEkxqG8HBGKwG9wXlZqg37RKSMY7v/X8VEWD8JG2JuTHuNK0VFvMPMUKQcbk6B+tf05k+4AShAEtCtJ/w==, } engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: @@ -2000,10 +2000,10 @@ packages: typescript: optional: true - "@typescript-eslint/visitor-keys@8.16.0": + "@typescript-eslint/visitor-keys@8.17.0": resolution: { - integrity: sha512-pq19gbaMOmFE3CbL0ZB8J8BFCo2ckfHBfaIsaOZgBIF4EoISJIdLX5xRhd0FGB0LlHReNRuzoJoMGpTjq8F2CQ==, + integrity: sha512-1Hm7THLpO6ww5QU6H/Qp+AusUUl+z/CAm3cNZZ0jQvon9yicgO7Rwd+/WWRpMKLYV6p2UvdbR27c86rzCPpreg==, } engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } @@ -3261,10 +3261,10 @@ packages: } engines: { node: ">= 0.4" } - has-symbols@1.0.3: + has-symbols@1.1.0: resolution: { - integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==, + integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==, } engines: { node: ">= 0.4" } @@ -3377,11 +3377,12 @@ packages: } engines: { node: ">= 0.4" } - is-bigint@1.0.4: + is-bigint@1.1.0: resolution: { - integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==, + integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==, } + engines: { node: ">= 0.4" } is-binary-path@2.1.0: resolution: @@ -3552,10 +3553,10 @@ packages: } engines: { node: ">= 0.4" } - is-symbol@1.0.4: + is-symbol@1.1.0: resolution: { - integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==, + integrity: sha512-qS8KkNNXUZ/I+nX6QT8ZS1/Yx0A444yhzdTKxCzKkNjQ9sHErBxJnJAgh+f5YhusYECEcjo4XcyH87hn6+ks0A==, } engines: { node: ">= 0.4" } @@ -4050,10 +4051,10 @@ packages: react-router-dom: optional: true - oauth4webapi@3.1.3: + oauth4webapi@3.1.4: resolution: { - integrity: sha512-dik5wEMdFL5p3JlijYvM7wMNCgaPhblLIDCZtdXcaZp5wgu5Iwmsu7lMzgFhIDTi5d0BJo03LVoOoFQvXMeOeQ==, + integrity: sha512-eVfN3nZNbok2s/ROifO0UAc5G8nRoLSbrcKJ09OqmucgnhXEfdIQOR4gq1eJH1rN3gV7rNw62bDEgftsgFtBEg==, } object-assign@4.1.1: @@ -4686,10 +4687,10 @@ packages: integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==, } - recharts@2.13.3: + recharts@2.14.0: resolution: { - integrity: sha512-YDZ9dOfK9t3ycwxgKbrnDlRC4BHdjlY73fet3a0C1+qGMjXVZe6+VXmpOIIhzkje5MMEL8AN4hLIe4AMskBzlA==, + integrity: sha512-kgDvDdNOh/gHQ4Q8hu7VrLNKs/bP/meG/XaRnsQG+Yp4PxugfPvaRFC0m4q7RWdlw0HxIkTSdcsGrsVQsg2qTA==, } engines: { node: ">=14" } peerDependencies: @@ -5173,10 +5174,10 @@ packages: } engines: { node: ">= 0.4" } - typescript-eslint@8.16.0: + typescript-eslint@8.17.0: resolution: { - integrity: sha512-wDkVmlY6O2do4V+lZd0GtRfbtXbeD0q9WygwXXSJnC1xorE8eqyC2L1tJimqpSeFrOzRlYtWnUp/uzgHQOgfBQ==, + integrity: sha512-409VXvFd/f1br1DCbuKNFqQpXICoTB+V51afcwG1pn1a3Cp92MqAUges3YjwEdQ0cMUoCIodjVDAYzyD8h3SYA==, } engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: @@ -5279,11 +5280,12 @@ packages: integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==, } - which-boxed-primitive@1.0.2: + which-boxed-primitive@1.1.0: resolution: { - integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==, + integrity: sha512-Ei7Miu/AXe2JJ4iNF5j/UphAgRoma4trE6PtisM09bPygb3egMH3YLW/befsWb1A1AxvNSFidOFTB18XtnIIng==, } + engines: { node: ">= 0.4" } which-builtin-type@1.2.0: resolution: @@ -5407,7 +5409,7 @@ snapshots: "@types/cookie": 0.6.0 cookie: 0.7.1 jose: 5.9.6 - oauth4webapi: 3.1.3 + oauth4webapi: 3.1.4 preact: 10.11.3 preact-render-to-string: 5.2.3(preact@10.11.3) @@ -5415,7 +5417,7 @@ snapshots: dependencies: "@panva/hkdf": 1.2.1 jose: 5.9.6 - oauth4webapi: 3.1.3 + oauth4webapi: 3.1.4 preact: 10.24.3 preact-render-to-string: 6.5.11(preact@10.24.3) @@ -6297,11 +6299,11 @@ snapshots: postcss-selector-parser: 6.0.10 tailwindcss: 3.4.15 - "@tanstack/query-core@5.62.0": {} + "@tanstack/query-core@5.62.1": {} - "@tanstack/react-query@5.62.0(react@18.3.1)": + "@tanstack/react-query@5.62.1(react@18.3.1)": dependencies: - "@tanstack/query-core": 5.62.0 + "@tanstack/query-core": 5.62.1 react: 18.3.1 "@tanstack/react-table@8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)": @@ -6544,14 +6546,14 @@ snapshots: "@types/wrap-ansi@3.0.0": {} - "@typescript-eslint/eslint-plugin@8.16.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)": + "@typescript-eslint/eslint-plugin@8.17.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)": dependencies: "@eslint-community/regexpp": 4.12.1 - "@typescript-eslint/parser": 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) - "@typescript-eslint/scope-manager": 8.16.0 - "@typescript-eslint/type-utils": 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) - "@typescript-eslint/utils": 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) - "@typescript-eslint/visitor-keys": 8.16.0 + "@typescript-eslint/parser": 8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + "@typescript-eslint/scope-manager": 8.17.0 + "@typescript-eslint/type-utils": 8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + "@typescript-eslint/utils": 8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + "@typescript-eslint/visitor-keys": 8.17.0 eslint: 9.16.0(jiti@1.21.6) graphemer: 1.4.0 ignore: 5.3.2 @@ -6562,12 +6564,12 @@ snapshots: transitivePeerDependencies: - supports-color - "@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)": + "@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)": dependencies: - "@typescript-eslint/scope-manager": 8.16.0 - "@typescript-eslint/types": 8.16.0 - "@typescript-eslint/typescript-estree": 8.16.0(typescript@5.7.2) - "@typescript-eslint/visitor-keys": 8.16.0 + "@typescript-eslint/scope-manager": 8.17.0 + "@typescript-eslint/types": 8.17.0 + "@typescript-eslint/typescript-estree": 8.17.0(typescript@5.7.2) + "@typescript-eslint/visitor-keys": 8.17.0 debug: 4.3.7 eslint: 9.16.0(jiti@1.21.6) optionalDependencies: @@ -6575,15 +6577,15 @@ snapshots: transitivePeerDependencies: - supports-color - "@typescript-eslint/scope-manager@8.16.0": + "@typescript-eslint/scope-manager@8.17.0": dependencies: - "@typescript-eslint/types": 8.16.0 - "@typescript-eslint/visitor-keys": 8.16.0 + "@typescript-eslint/types": 8.17.0 + "@typescript-eslint/visitor-keys": 8.17.0 - "@typescript-eslint/type-utils@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)": + "@typescript-eslint/type-utils@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)": dependencies: - "@typescript-eslint/typescript-estree": 8.16.0(typescript@5.7.2) - "@typescript-eslint/utils": 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + "@typescript-eslint/typescript-estree": 8.17.0(typescript@5.7.2) + "@typescript-eslint/utils": 8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) debug: 4.3.7 eslint: 9.16.0(jiti@1.21.6) ts-api-utils: 1.4.3(typescript@5.7.2) @@ -6592,12 +6594,12 @@ snapshots: transitivePeerDependencies: - supports-color - "@typescript-eslint/types@8.16.0": {} + "@typescript-eslint/types@8.17.0": {} - "@typescript-eslint/typescript-estree@8.16.0(typescript@5.7.2)": + "@typescript-eslint/typescript-estree@8.17.0(typescript@5.7.2)": dependencies: - "@typescript-eslint/types": 8.16.0 - "@typescript-eslint/visitor-keys": 8.16.0 + "@typescript-eslint/types": 8.17.0 + "@typescript-eslint/visitor-keys": 8.17.0 debug: 4.3.7 fast-glob: 3.3.2 is-glob: 4.0.3 @@ -6609,21 +6611,21 @@ snapshots: transitivePeerDependencies: - supports-color - "@typescript-eslint/utils@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)": + "@typescript-eslint/utils@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)": dependencies: "@eslint-community/eslint-utils": 4.4.1(eslint@9.16.0(jiti@1.21.6)) - "@typescript-eslint/scope-manager": 8.16.0 - "@typescript-eslint/types": 8.16.0 - "@typescript-eslint/typescript-estree": 8.16.0(typescript@5.7.2) + "@typescript-eslint/scope-manager": 8.17.0 + "@typescript-eslint/types": 8.17.0 + "@typescript-eslint/typescript-estree": 8.17.0(typescript@5.7.2) eslint: 9.16.0(jiti@1.21.6) optionalDependencies: typescript: 5.7.2 transitivePeerDependencies: - supports-color - "@typescript-eslint/visitor-keys@8.16.0": + "@typescript-eslint/visitor-keys@8.17.0": dependencies: - "@typescript-eslint/types": 8.16.0 + "@typescript-eslint/types": 8.17.0 eslint-visitor-keys: 4.2.0 acorn-jsx@5.3.2(acorn@8.14.0): @@ -7047,7 +7049,7 @@ snapshots: gopd: 1.1.0 has-property-descriptors: 1.0.2 has-proto: 1.1.0 - has-symbols: 1.0.3 + has-symbols: 1.1.0 hasown: 2.0.2 internal-slot: 1.0.7 is-array-buffer: 3.0.4 @@ -7094,7 +7096,7 @@ snapshots: gopd: 1.1.0 has-property-descriptors: 1.0.2 has-proto: 1.1.0 - has-symbols: 1.0.3 + has-symbols: 1.1.0 internal-slot: 1.0.7 iterator.prototype: 1.1.3 safe-array-concat: 1.1.2 @@ -7117,7 +7119,7 @@ snapshots: dependencies: is-callable: 1.2.7 is-date-object: 1.0.5 - is-symbol: 1.0.4 + is-symbol: 1.1.0 escape-string-regexp@4.0.0: {} @@ -7125,12 +7127,12 @@ snapshots: dependencies: "@next/eslint-plugin-next": 14.2.18 "@rushstack/eslint-patch": 1.10.4 - "@typescript-eslint/eslint-plugin": 8.16.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) - "@typescript-eslint/parser": 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + "@typescript-eslint/eslint-plugin": 8.17.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + "@typescript-eslint/parser": 8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) eslint: 9.16.0(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.16.0(jiti@1.21.6)) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.16.0(jiti@1.21.6)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.16.0(jiti@1.21.6)) eslint-plugin-react: 7.37.2(eslint@9.16.0(jiti@1.21.6)) eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@9.16.0(jiti@1.21.6)) @@ -7149,37 +7151,37 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.16.0(jiti@1.21.6)): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.16.0(jiti@1.21.6)): dependencies: "@nolyfill/is-core-module": 1.0.39 debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 9.16.0(jiti@1.21.6) - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.3.0 is-glob: 4.0.3 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)) transitivePeerDependencies: - "@typescript-eslint/parser" - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)): dependencies: debug: 3.2.7 optionalDependencies: - "@typescript-eslint/parser": 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + "@typescript-eslint/parser": 8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) eslint: 9.16.0(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.16.0(jiti@1.21.6)) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.16.0(jiti@1.21.6)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)): dependencies: "@rtsao/scc": 1.1.0 array-includes: 3.1.8 @@ -7190,7 +7192,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.16.0(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -7202,7 +7204,7 @@ snapshots: string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: - "@typescript-eslint/parser": 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + "@typescript-eslint/parser": 8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -7261,11 +7263,11 @@ snapshots: dependencies: eslint: 9.16.0(jiti@1.21.6) - eslint-plugin-unused-imports@4.1.4(@typescript-eslint/eslint-plugin@8.16.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6)): + eslint-plugin-unused-imports@4.1.4(@typescript-eslint/eslint-plugin@8.17.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6)): dependencies: eslint: 9.16.0(jiti@1.21.6) optionalDependencies: - "@typescript-eslint/eslint-plugin": 8.16.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + "@typescript-eslint/eslint-plugin": 8.17.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) eslint-scope@8.2.0: dependencies: @@ -7436,7 +7438,7 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 has-proto: 1.1.0 - has-symbols: 1.0.3 + has-symbols: 1.1.0 hasown: 2.0.2 get-nonce@1.0.1: {} @@ -7507,11 +7509,11 @@ snapshots: dependencies: call-bind: 1.0.7 - has-symbols@1.0.3: {} + has-symbols@1.1.0: {} has-tostringtag@1.0.2: dependencies: - has-symbols: 1.0.3 + has-symbols: 1.1.0 hasown@2.0.2: dependencies: @@ -7566,7 +7568,7 @@ snapshots: dependencies: has-tostringtag: 1.0.2 - is-bigint@1.0.4: + is-bigint@1.1.0: dependencies: has-bigints: 1.0.2 @@ -7652,9 +7654,11 @@ snapshots: call-bind: 1.0.7 has-tostringtag: 1.0.2 - is-symbol@1.0.4: + is-symbol@1.1.0: dependencies: - has-symbols: 1.0.3 + call-bind: 1.0.7 + has-symbols: 1.1.0 + safe-regex-test: 1.0.3 is-typed-array@1.1.13: dependencies: @@ -7691,7 +7695,7 @@ snapshots: dependencies: define-properties: 1.2.1 get-intrinsic: 1.2.4 - has-symbols: 1.0.3 + has-symbols: 1.1.0 reflect.getprototypeof: 1.0.7 set-function-name: 2.0.2 @@ -7904,7 +7908,7 @@ snapshots: optionalDependencies: next: 14.2.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - oauth4webapi@3.1.3: {} + oauth4webapi@3.1.4: {} object-assign@4.1.1: {} @@ -7918,7 +7922,7 @@ snapshots: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - has-symbols: 1.0.3 + has-symbols: 1.1.0 object-keys: 1.1.1 object.entries@1.1.8: @@ -8310,7 +8314,7 @@ snapshots: dependencies: decimal.js-light: 2.5.1 - recharts@2.13.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + recharts@2.14.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: clsx: 2.1.1 eventemitter3: 4.0.7 @@ -8377,7 +8381,7 @@ snapshots: dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 - has-symbols: 1.0.3 + has-symbols: 1.1.0 isarray: 2.0.5 safe-regex-test@1.0.3: @@ -8473,7 +8477,7 @@ snapshots: es-object-atoms: 1.0.0 get-intrinsic: 1.2.4 gopd: 1.1.0 - has-symbols: 1.0.3 + has-symbols: 1.1.0 internal-slot: 1.0.7 regexp.prototype.flags: 1.5.3 set-function-name: 2.0.2 @@ -8651,11 +8655,11 @@ snapshots: possible-typed-array-names: 1.0.0 reflect.getprototypeof: 1.0.7 - typescript-eslint@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2): + typescript-eslint@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2): dependencies: - "@typescript-eslint/eslint-plugin": 8.16.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) - "@typescript-eslint/parser": 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) - "@typescript-eslint/utils": 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + "@typescript-eslint/eslint-plugin": 8.17.0(@typescript-eslint/parser@8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + "@typescript-eslint/parser": 8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + "@typescript-eslint/utils": 8.17.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) eslint: 9.16.0(jiti@1.21.6) optionalDependencies: typescript: 5.7.2 @@ -8670,8 +8674,8 @@ snapshots: dependencies: call-bind: 1.0.7 has-bigints: 1.0.2 - has-symbols: 1.0.3 - which-boxed-primitive: 1.0.2 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.0 undici-types@6.20.0: {} @@ -8728,13 +8732,13 @@ snapshots: w3c-keyname@2.2.8: {} - which-boxed-primitive@1.0.2: + which-boxed-primitive@1.1.0: dependencies: - is-bigint: 1.0.4 + is-bigint: 1.1.0 is-boolean-object: 1.2.0 is-number-object: 1.1.0 is-string: 1.1.0 - is-symbol: 1.0.4 + is-symbol: 1.1.0 which-builtin-type@1.2.0: dependencies: @@ -8748,7 +8752,7 @@ snapshots: is-regex: 1.2.0 is-weakref: 1.0.2 isarray: 2.0.5 - which-boxed-primitive: 1.0.2 + which-boxed-primitive: 1.1.0 which-collection: 1.0.2 which-typed-array: 1.1.16 diff --git a/src/app/portal/dashboard/page.tsx b/src/app/portal/dashboard/page.tsx index 40e6a1a..7f32bab 100644 --- a/src/app/portal/dashboard/page.tsx +++ b/src/app/portal/dashboard/page.tsx @@ -1,28 +1,29 @@ -import { Folder, Newspaper, User } from "lucide-react"; - import { ContentLayout } from "@/components/admin-panel/content-layout"; -import DashboardCard from "@/components/dashboard/dashboard-card"; +import RecentUserTeamActivities from "@/components/dashboard/global-dashboard-recent-activities"; +import UserNotifications from "@/components/dashboard/notifications-user"; +import TeamUnresolvedTicketsPriorityDistributionChart from "@/components/dashboard/team-unresolved-tickets-priority-distribution"; +import UserTeamsOverdueTickets from "@/components/dashboard/user-requests-overdue"; export default function Home() { return (

Dashboard

-
- } - /> - } - /> - } - /> + +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
); diff --git a/src/components/dashboard/dashboard-card.tsx b/src/components/dashboard/dashboard-card.tsx deleted file mode 100644 index 3f68ea2..0000000 --- a/src/components/dashboard/dashboard-card.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { LucideIcon } from "lucide-react"; -import React from "react"; - -import { Card, CardContent } from "@/components/ui/card"; - -interface DashboardCardProps { - title: string; - count: number; - icon: React.ReactElement; -} -const DashboardCard = ({ title, count, icon }: DashboardCardProps) => { - return ( - - -

- {title} -

-
- {icon} -

{count}

-
-
-
- ); -}; - -export default DashboardCard; diff --git a/src/components/dashboard/global-dashboard-recent-activities.tsx b/src/components/dashboard/global-dashboard-recent-activities.tsx new file mode 100644 index 0000000..86ebdd0 --- /dev/null +++ b/src/components/dashboard/global-dashboard-recent-activities.tsx @@ -0,0 +1,97 @@ +"use client"; + +import Link from "next/link"; +import { useSession } from "next-auth/react"; +import React, { useEffect, useState } from "react"; + +import PaginationExt from "@/components/shared/pagination-ext"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Spinner } from "@/components/ui/spinner"; +import { getUserActivities } from "@/lib/actions/activity-logs.action"; +import { formatDateTimeDistanceToNow } from "@/lib/datetime"; +import { obfuscate } from "@/lib/endecode"; +import { ActivityLogDTO } from "@/types/activity-logs"; + +const RecentUserTeamActivities = () => { + const [activityLogs, setActivityLogs] = useState([]); + const [currentPage, setCurrentPage] = useState(1); + const [totalPages, setTotalPages] = useState(0); + const [loading, setLoading] = useState(false); + + const { data: session } = useSession(); + const userId = Number(session?.user?.id!); + + useEffect(() => { + async function fetchActivityLogs() { + setLoading(true); + getUserActivities(userId, currentPage, 5) + .then((data) => { + setActivityLogs(data.content); + setTotalPages(data.totalPages); + }) + .finally(() => setLoading(false)); + } + fetchActivityLogs(); + }, [userId, currentPage]); + + return ( + + + Recent Activities + + + {loading ? ( +
+ + Loading data ... + +
+ ) : activityLogs && activityLogs.length > 0 ? ( +
+ {activityLogs.map((activityLog, index) => ( +
+ +
+

+ Modified at:{" "} + {formatDateTimeDistanceToNow(new Date(activityLog.createdAt))} +

+
+ ))} +
+ ) : ( +

+ No activity logs available +

+ )} + setCurrentPage(page)} + className="pt-2" + /> + + + ); +}; + +export default RecentUserTeamActivities; diff --git a/src/components/dashboard/notifications-dropdown.tsx b/src/components/dashboard/notifications-dropdown.tsx index cb1fe43..b99398b 100644 --- a/src/components/dashboard/notifications-dropdown.tsx +++ b/src/components/dashboard/notifications-dropdown.tsx @@ -80,22 +80,23 @@ const NotificationsDropdown = () => { { "backdrop-blur-md backdrop-brightness-110 dark:backdrop-brightness-75 shadow-lg", )} > - {notifications.length > 0 ? ( + {notifications && notifications.length > 0 ? ( <>
diff --git a/src/components/dashboard/notifications-user.tsx b/src/components/dashboard/notifications-user.tsx new file mode 100644 index 0000000..e1e57c2 --- /dev/null +++ b/src/components/dashboard/notifications-user.tsx @@ -0,0 +1,115 @@ +"use client"; + +import { useSession } from "next-auth/react"; +import React, { useEffect, useState } from "react"; + +import PaginationExt from "@/components/shared/pagination-ext"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Spinner } from "@/components/ui/spinner"; +import { + getUserNotifications, + markNotificationsAsRead, +} from "@/lib/actions/notifications.action"; +import { formatDateTimeDistanceToNow } from "@/lib/datetime"; +import { NotificationDTO } from "@/types/commons"; + +const UserNotifications = () => { + const [notifications, setNotifications] = useState([]); + const [currentPage, setCurrentPage] = useState(1); + const [totalPages, setTotalPages] = useState(0); + const [loading, setLoading] = useState(false); + + const { data: session } = useSession(); + const userId = Number(session?.user?.id!); + + useEffect(() => { + async function fetchNotifications() { + setLoading(true); + getUserNotifications(userId, currentPage, 5) + .then((data) => { + setNotifications(data.content); + setTotalPages(data.totalPages); + }) + .finally(() => setLoading(false)); + } + fetchNotifications(); + }, [userId, currentPage]); + + const handleMarkAsRead = async (notificationId: number) => { + try { + await markNotificationsAsRead([notificationId]); + setNotifications((prev) => + prev.map((n) => (n.id === notificationId ? { ...n, isRead: true } : n)), + ); + } catch (error) { + console.error("Failed to mark notification as read", error); + } + }; + + return ( + + + Notifications + + + {loading ? ( +
+ + Loading data ... + +
+ ) : notifications && notifications.length > 0 ? ( +
+ {notifications.map((notification, index) => ( +
+
+

+ Created at:{" "} + {formatDateTimeDistanceToNow( + new Date(notification.createdAt), + )} +

+ {!notification.isRead && ( + + )} +
+ ))} +
+ ) : ( +

+ No notification available +

+ )} + setCurrentPage(page)} + className="pt-2" + /> + + + ); +}; + +export default UserNotifications; diff --git a/src/components/dashboard/team-unresolved-tickets-priority-distribution.tsx b/src/components/dashboard/team-unresolved-tickets-priority-distribution.tsx new file mode 100644 index 0000000..d7330ec --- /dev/null +++ b/src/components/dashboard/team-unresolved-tickets-priority-distribution.tsx @@ -0,0 +1,129 @@ +"use client"; + +import { useSession } from "next-auth/react"; +import React, { useEffect, useState } from "react"; +import { + Bar, + BarChart, + CartesianGrid, + Legend, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from "recharts"; + +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Spinner } from "@/components/ui/spinner"; +import { getTeamTicketPriorityDistributionForUser } from "@/lib/actions/teams-request.action"; +import { TeamRequestPriority } from "@/types/team-requests"; + +const TeamUnresolvedTicketsPriorityDistributionChart = () => { + const { data: session } = useSession(); + const userId = Number(session?.user?.id!); + + const [data, setData] = useState< + Record> + >({}); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const fetchData = async () => { + getTeamTicketPriorityDistributionForUser(userId) + .then((result) => { + const chartData = result.reduce( + (acc, item) => { + if (!acc[item.teamName]) { + acc[item.teamName] = { + Critical: 0, + High: 0, + Medium: 0, + Low: 0, + Trivial: 0, + }; + } + acc[item.teamName][item.priority] = item.count; + return acc; + }, + {} as Record>, + ); + + setData(chartData); + }) + .finally(() => setLoading(false)); + }; + + fetchData(); + }, []); + + const chartData = Object.entries(data).map(([teamName, priorities]) => ({ + teamName, + ...priorities, + })); + + return ( + + + Unresolved Tickets by Team + + + + {loading ? ( +
+ +
+ ) : chartData.length === 0 ? ( +
+

No data available to display.

+
+ ) : ( + + + + + + + {/* Red */} + {/* Orange */} + {/* Yellow */} + {/* Green */} + {/* Gray */} + + )} +
+
+
+ ); +}; + +export default TeamUnresolvedTicketsPriorityDistributionChart; diff --git a/src/components/dashboard/user-requests-overdue.tsx b/src/components/dashboard/user-requests-overdue.tsx new file mode 100644 index 0000000..20b9aa9 --- /dev/null +++ b/src/components/dashboard/user-requests-overdue.tsx @@ -0,0 +1,178 @@ +"use client"; + +import { ChevronDown, ChevronUp } from "lucide-react"; +import Link from "next/link"; +import { useSession } from "next-auth/react"; +import React, { useEffect, useState } from "react"; + +import { UserAvatar } from "@/components/shared/avatar-display"; +import PaginationExt from "@/components/shared/pagination-ext"; +import TruncatedHtmlLabel from "@/components/shared/truncate-html-label"; +import { PriorityDisplay } from "@/components/teams/team-requests-priority-display"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Spinner } from "@/components/ui/spinner"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { getOverdueTicketsByUser } from "@/lib/actions/teams-request.action"; +import { formatDateTimeDistanceToNow } from "@/lib/datetime"; +import { obfuscate } from "@/lib/endecode"; +import { TeamRequestDTO, TeamRequestPriority } from "@/types/team-requests"; + +const UserTeamsOverdueTickets = () => { + const { data: session } = useSession(); + const userId = Number(session?.user?.id!); + const [currentPage, setCurrentPage] = useState(1); + const [totalPages, setTotalPages] = useState(0); + const [totalTickets, setTotalTickets] = useState(0); + const [tickets, setTickets] = useState([]); + const [loading, setLoading] = useState(false); + + const [sortBy, setSortBy] = useState("priority"); + const [sortDirection, setSortDirection] = useState<"asc" | "desc">("asc"); + + useEffect(() => { + const fetchData = async () => { + setLoading(true); + getOverdueTicketsByUser(userId, currentPage, sortBy, sortDirection) + .then((data) => { + setTickets(data.content); + setTotalPages(data.totalPages); + setTotalTickets(data.totalElements); + }) + .finally(() => setLoading(false)); + }; + + fetchData(); + }, [userId, currentPage, sortBy, sortDirection]); + + const toggleSortDirection = () => { + setSortDirection((prev) => (prev === "asc" ? "desc" : "asc")); + }; + + return ( + + +
+ Overdue Tickets ({totalTickets}) +
+ + + + + + {sortDirection === "asc" + ? "Sort by priority: Ascending" + : "Sort by priority: Descending"} + + +
+
+
+ + {loading ? ( +
+ + Loading data ... + +
+ ) : ( +
+ {tickets.length > 0 ? ( + tickets.map((ticket, index) => ( +
+
+ +
+ +
+
+ +
+ Assignee: + {ticket.assignUserId ? ( + <> + + + + ) : ( + Unassigned + )} +
+

+ Modified at:{" "} + {formatDateTimeDistanceToNow(ticket.modifiedAt)} +

+
+ )) + ) : ( +

+ No overdue tickets available +

+ )} +
+ )} + + setCurrentPage(page)} + className="pt-2" + /> +
+
+ ); +}; + +export default UserTeamsOverdueTickets; diff --git a/src/components/shared/audit-log-view.tsx b/src/components/shared/audit-log-view.tsx index 4c6ed1c..2aa80f4 100644 --- a/src/components/shared/audit-log-view.tsx +++ b/src/components/shared/audit-log-view.tsx @@ -22,7 +22,7 @@ const AuditLogView: React.FC = ({ entityType, entityId, }) => { - const [logs, setLogs] = useState([]); + const [activityLogs, setActivityLogs] = useState([]); const [loading, setLoading] = useState(false); const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(0); @@ -33,7 +33,7 @@ const AuditLogView: React.FC = ({ getActivityLogs("Team_Request", entityId, currentPage) .then((data) => { setTotalPages(data.totalPages); - setLogs(data.content); + setActivityLogs(data.content); }) .finally(() => setLoading(false)); }; @@ -44,13 +44,13 @@ const AuditLogView: React.FC = ({ return
Loading history...
; } - if (logs.length === 0) { + if (activityLogs.length === 0) { return
No history available.
; } return (
- {logs.map((log, index) => ( + {activityLogs.map((activityLog, index) => (
= ({ )} >
- + made some changes @@ -71,11 +76,12 @@ const AuditLogView: React.FC = ({
- Updated: {formatDateTimeDistanceToNow(new Date(log.createdAt))} + Updated:{" "} + {formatDateTimeDistanceToNow(new Date(activityLog.createdAt))}
))} diff --git a/src/components/teams/team-dashboard-recent-activity.tsx b/src/components/teams/team-dashboard-recent-activities.tsx similarity index 89% rename from src/components/teams/team-dashboard-recent-activity.tsx rename to src/components/teams/team-dashboard-recent-activities.tsx index edc0b2a..66f1409 100644 --- a/src/components/teams/team-dashboard-recent-activity.tsx +++ b/src/components/teams/team-dashboard-recent-activities.tsx @@ -8,13 +8,8 @@ import { Spinner } from "@/components/ui/spinner"; import { getActivityLogs } from "@/lib/actions/activity-logs.action"; import { formatDateTimeDistanceToNow } from "@/lib/datetime"; import { ActivityLogDTO } from "@/types/activity-logs"; -import { TeamDTO } from "@/types/teams"; -type DashboardTrendsAndActivityProps = { - team: TeamDTO; -}; - -const RecentTeamActivities = ({ team }: DashboardTrendsAndActivityProps) => { +const RecentTeamActivities = ({ teamId }: { teamId: number }) => { const [activityLogs, setActivityLogs] = useState([]); const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(0); @@ -23,7 +18,7 @@ const RecentTeamActivities = ({ team }: DashboardTrendsAndActivityProps) => { useEffect(() => { async function fetchActivityLogs() { setLoading(true); - getActivityLogs("Team", team.id!, currentPage, 5) + getActivityLogs("Team", teamId, currentPage, 5) .then((data) => { setActivityLogs(data.content); setTotalPages(data.totalPages); @@ -31,12 +26,12 @@ const RecentTeamActivities = ({ team }: DashboardTrendsAndActivityProps) => { .finally(() => setLoading(false)); } fetchActivityLogs(); - }, [team, currentPage]); + }, [teamId, currentPage]); return ( - Recent Activity + Recent Activities {loading ? ( diff --git a/src/components/teams/team-dashboard.tsx b/src/components/teams/team-dashboard.tsx index 3241ed2..6cf56b4 100644 --- a/src/components/teams/team-dashboard.tsx +++ b/src/components/teams/team-dashboard.tsx @@ -7,10 +7,10 @@ import React from "react"; import { Heading } from "@/components/heading"; import { TeamAvatar } from "@/components/shared/avatar-display"; import TeamDashboardTopSection from "@/components/teams/team-dashboard-kpis"; -import RecentTeamActivities from "@/components/teams/team-dashboard-recent-activity"; +import RecentTeamActivities from "@/components/teams/team-dashboard-recent-activities"; import TicketCreationByDaySeriesChart from "@/components/teams/team-requests-creation-timeseries-chart"; import TicketDistributionChart from "@/components/teams/team-requests-distribution-chart"; -import OverdueTickets from "@/components/teams/team-requests-overdue"; +import TeamOverdueTickets from "@/components/teams/team-requests-overdue"; import TicketPriorityPieChart from "@/components/teams/team-requests-priority-chart"; import UnassignedTickets from "@/components/teams/team-requests-unassigned"; import { buttonVariants } from "@/components/ui/button"; @@ -69,7 +69,7 @@ const TeamDashboard = ({ entity: team }: ViewProps) => {
- +
@@ -77,7 +77,7 @@ const TeamDashboard = ({ entity: team }: ViewProps) => {
- +
diff --git a/src/components/teams/team-list.tsx b/src/components/teams/team-list.tsx index 1477e73..c88e886 100644 --- a/src/components/teams/team-list.tsx +++ b/src/components/teams/team-list.tsx @@ -10,6 +10,7 @@ import { } from "lucide-react"; import Link from "next/link"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; +import { useSession } from "next-auth/react"; import React, { useEffect, useState } from "react"; import { Heading } from "@/components/heading"; @@ -19,6 +20,7 @@ import PaginationExt from "@/components/shared/pagination-ext"; import DefaultTeamLogo from "@/components/teams/team-logo"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Button, buttonVariants } from "@/components/ui/button"; +import { Checkbox } from "@/components/ui/checkbox"; import { DropdownMenu, DropdownMenuContent, @@ -38,12 +40,13 @@ import { usePagePermission } from "@/hooks/use-page-permission"; import { deleteTeams, searchTeams } from "@/lib/actions/teams.action"; import { obfuscate } from "@/lib/endecode"; import { cn } from "@/lib/utils"; -import { QueryDTO } from "@/types/query"; +import { Filter, QueryDTO } from "@/types/query"; import { PermissionUtils } from "@/types/resources"; import { TeamDTO } from "@/types/teams"; export const TeamList = () => { const router = useRouter(); + const { data: session } = useSession(); const [items, setItems] = useState>([]); const [teamSearchTerm, setTeamSearchTerm] = useState( undefined, @@ -53,6 +56,7 @@ export const TeamList = () => { const [totalElements, setTotalElements] = useState(0); const [loading, setLoading] = useState(false); const [sortDirection, setSortDirection] = useState<"asc" | "desc">("asc"); + const [filterUserTeamsOnly, setFilterUserTeamsOnly] = useState(true); const [isDialogOpen, setDialogOpen] = useState(false); const [selectedTeam, setSelectedTeam] = useState(null); @@ -66,16 +70,24 @@ export const TeamList = () => { const fetchData = async () => { setLoading(true); try { + const filters: Filter[] = []; + if (teamSearchTerm) { + filters.push({ + field: "name", + operator: "lk", + value: teamSearchTerm, + }); + } + if (filterUserTeamsOnly) { + filters.push({ + field: "users.id", + operator: "eq", + value: Number(session?.user?.id!), + }); + } + const query: QueryDTO = { - filters: teamSearchTerm - ? [ - { - field: "name", - operator: "lk", - value: teamSearchTerm, - }, - ] - : [], + filters, }; const pageResult = await searchTeams(query, { @@ -88,9 +100,11 @@ export const TeamList = () => { }, ], }); - setItems(pageResult.content); - setTotalElements(pageResult.totalElements); - setTotalPages(pageResult.totalPages); + if (pageResult) { + setItems(pageResult.content); + setTotalElements(pageResult.totalElements); + setTotalPages(pageResult.totalPages); + } } finally { setLoading(false); } @@ -113,7 +127,7 @@ export const TeamList = () => { useEffect(() => { fetchData(); - }, [teamSearchTerm, currentPage, sortDirection]); + }, [teamSearchTerm, currentPage, sortDirection, filterUserTeamsOnly]); const showDeleteTeamConfirmationDialog = (team: TeamDTO) => { setSelectedTeam(team); @@ -144,6 +158,16 @@ export const TeamList = () => { +
+ setFilterUserTeamsOnly(!!checked)} + /> + +
{PermissionUtils.canWrite(permissionLevel) && ( = ({ useEffect(() => { const fetchData = async () => { setLoading(true); - getTicketsAssignmentDistribution(teamId) + getTicketsAssignmentDistributionByTeam(teamId) .then((data) => setData(data)) .finally(() => setLoading(false)); }; @@ -110,6 +110,7 @@ const TicketDistributionChart: React.FC = ({ data={chartData} layout="vertical" margin={{ top: 20, right: 30, left: 20, bottom: 5 }} + barSize={40} // Set a fixed bar size > diff --git a/src/components/teams/team-requests-overdue.tsx b/src/components/teams/team-requests-overdue.tsx index 0f9de28..99e9ca1 100644 --- a/src/components/teams/team-requests-overdue.tsx +++ b/src/components/teams/team-requests-overdue.tsx @@ -9,18 +9,18 @@ import TruncatedHtmlLabel from "@/components/shared/truncate-html-label"; import { PriorityDisplay } from "@/components/teams/team-requests-priority-display"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Spinner } from "@/components/ui/spinner"; // Add your spinner component +import { Spinner } from "@/components/ui/spinner"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; -import { getOverdueTickets } from "@/lib/actions/teams-request.action"; +import { getOverdueTicketsByTeam } from "@/lib/actions/teams-request.action"; import { formatDateTimeDistanceToNow } from "@/lib/datetime"; import { obfuscate } from "@/lib/endecode"; import { TeamRequestDTO, TeamRequestPriority } from "@/types/team-requests"; -const OverdueTickets = ({ teamId }: { teamId: number }) => { +const TeamOverdueTickets = ({ teamId }: { teamId: number }) => { const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(0); const [totalTickets, setTotalTickets] = useState(0); @@ -28,12 +28,12 @@ const OverdueTickets = ({ teamId }: { teamId: number }) => { const [loading, setLoading] = useState(false); const [sortBy, setSortBy] = useState("priority"); - const [sortDirection, setSortDirection] = useState<"asc" | "desc">("desc"); + const [sortDirection, setSortDirection] = useState<"asc" | "desc">("asc"); useEffect(() => { const fetchData = async () => { setLoading(true); - getOverdueTickets(teamId, currentPage, sortBy, sortDirection) + getOverdueTicketsByTeam(teamId, currentPage, sortBy, sortDirection) .then((data) => { setTickets(data.content); setTotalPages(data.totalPages); @@ -62,7 +62,7 @@ const OverdueTickets = ({ teamId }: { teamId: number }) => { onClick={toggleSortDirection} className="p-2 flex items-center gap-2" > - {sortDirection === "asc" ? ( + {sortDirection === "desc" ? ( ) : ( @@ -151,4 +151,4 @@ const OverdueTickets = ({ teamId }: { teamId: number }) => { ); }; -export default OverdueTickets; +export default TeamOverdueTickets; diff --git a/src/components/teams/team-requests-priority-chart.tsx b/src/components/teams/team-requests-priority-chart.tsx index da22306..981a8f2 100644 --- a/src/components/teams/team-requests-priority-chart.tsx +++ b/src/components/teams/team-requests-priority-chart.tsx @@ -12,7 +12,7 @@ import { import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Spinner } from "@/components/ui/spinner"; // Import your spinner component -import { getTicketsPriorityDistribution } from "@/lib/actions/teams-request.action"; +import { getTicketsPriorityDistributionByTeam } from "@/lib/actions/teams-request.action"; import { PriorityDistributionDTO } from "@/types/team-requests"; import { TeamRequestPriority } from "@/types/team-requests"; @@ -26,7 +26,7 @@ const TicketPriorityPieChart = ({ teamId }: { teamId: number }) => { // Fetch priority distribution data const fetchPriorityData = async () => { setLoading(true); - getTicketsPriorityDistribution(teamId) + getTicketsPriorityDistributionByTeam(teamId) .then((data) => setPriorityData(data)) .finally(() => setLoading(false)); }; @@ -34,13 +34,14 @@ const TicketPriorityPieChart = ({ teamId }: { teamId: number }) => { fetchPriorityData(); }, [teamId]); - // Define colors for the pie chart based on TeamRequestPriority + // Define colors for the pie chart based on TeamRequestPriority, this color should match with color + // defines at team-request-priority-display.tsx const COLORS: Record = { - Critical: "#FF4500", - High: "#FF6384", - Medium: "#36A2EB", - Low: "#FFCE56", - Trivial: "#00FF00", + Critical: "#DC2626", // text-red-600 + High: "#F97316", // text-orange-500 + Medium: "#F59E0B", // text-yellow-500 + Low: "#16A34A", // text-green-500 + Trivial: "#9CA3AF", // text-gray-400 }; return ( diff --git a/src/components/teams/team-requests-unassigned.tsx b/src/components/teams/team-requests-unassigned.tsx index 4eb4931..fc22fe3 100644 --- a/src/components/teams/team-requests-unassigned.tsx +++ b/src/components/teams/team-requests-unassigned.tsx @@ -62,7 +62,7 @@ const UnassignedTickets = ({ teamId }: { teamId: number }) => { onClick={toggleSortDirection} className="p-2 flex items-center gap-2" > - {sortDirection === "asc" ? ( + {sortDirection === "desc" ? ( ) : ( diff --git a/src/lib/actions/activity-logs.action.ts b/src/lib/actions/activity-logs.action.ts index d83f9f1..9b798cf 100644 --- a/src/lib/actions/activity-logs.action.ts +++ b/src/lib/actions/activity-logs.action.ts @@ -12,6 +12,16 @@ export const getActivityLogs = async ( displayNumber = 10, ) => { return get>( - `${BACKEND_API}/api/activity-logs?entityType=${entityType}&&entityId=${entityId}&&page=${page - 1}&&size=${displayNumber}&&sortBy=createdAt&&sortDirection=desc`, + `${BACKEND_API}/api/activity-logs?entityType=${entityType}&entityId=${entityId}&page=${page}&size=${displayNumber}&sort=createdAt,desc`, + ); +}; + +export const getUserActivities = async ( + userId: number, + page: number, + displayNumber = 10, +) => { + return get>( + `${BACKEND_API}/api/activity-logs/user/${userId}?page=${page}&size=${displayNumber}&sort=createdAt,desc`, ); }; diff --git a/src/lib/actions/notifications.action.ts b/src/lib/actions/notifications.action.ts index 434035f..98d5e64 100644 --- a/src/lib/actions/notifications.action.ts +++ b/src/lib/actions/notifications.action.ts @@ -2,7 +2,7 @@ import { get, post } from "@/lib/actions/commons.action"; import { BACKEND_API } from "@/lib/constants"; -import { NotificationDTO } from "@/types/commons"; +import { NotificationDTO, PageableResult } from "@/types/commons"; export async function getUnReadNotificationsByUserId(userId: number) { return get>( @@ -17,3 +17,13 @@ export async function markNotificationsAsRead( notificationIds: notificationIds, }); } + +export async function getUserNotifications( + userId: number, + page: number, + displayNumber = 10, +) { + return get>( + `${BACKEND_API}/api/notifications/user/${userId}?page=${page}&size=${displayNumber}&sort=createdAt,desc`, + ); +} diff --git a/src/lib/actions/teams-request.action.ts b/src/lib/actions/teams-request.action.ts index 72cf0c7..23b0fbf 100644 --- a/src/lib/actions/teams-request.action.ts +++ b/src/lib/actions/teams-request.action.ts @@ -12,7 +12,10 @@ import { TicketDistributionDTO, TicketStatisticsDTO, } from "@/types/team-requests"; -import { TicketActionCountByDateDTO } from "@/types/teams"; +import { + TeamTicketPriorityDistributionDTO, + TicketActionCountByDateDTO, +} from "@/types/teams"; export const createTeamRequest = async (teamRequest: TeamRequestDTO) => { return post( @@ -60,15 +63,17 @@ export const findNextTeamRequest = async (requestId: number) => { ); }; -export const getTicketsAssignmentDistribution = async (teamId: number) => { +export const getTicketsAssignmentDistributionByTeam = async ( + teamId: number, +) => { return get( - `${BACKEND_API}/api/team-requests/${teamId}/ticket-distribution`, + `${BACKEND_API}/api/team-requests/teams/${teamId}/ticket-distribution`, ); }; -export const getTicketsPriorityDistribution = async (teamId: number) => { +export const getTicketsPriorityDistributionByTeam = async (teamId: number) => { return get( - `${BACKEND_API}/api/team-requests/${teamId}/priority-distribution`, + `${BACKEND_API}/api/team-requests/teams/${teamId}/priority-distribution`, ); }; @@ -79,30 +84,30 @@ export const getUnassignedTickets = async ( sortDirection: string, ) => { return get>( - `${BACKEND_API}/api/team-requests/${teamId}/unassigned-tickets?page=${page}&size=5&sort=${sortBy},${sortDirection}`, + `${BACKEND_API}/api/team-requests/teams/${teamId}/unassigned-tickets?page=${page}&size=5&sort=${sortBy},${sortDirection}`, ); }; -export const getOverdueTickets = async ( +export const getOverdueTicketsByTeam = async ( teamId: number, page: number, sortBy: string, sortDirection: string, ) => { return get>( - `${BACKEND_API}/api/team-requests/${teamId}/overdue-tickets?page=${page}&size=5&sort=${sortBy},${sortDirection}`, + `${BACKEND_API}/api/team-requests/teams/${teamId}/overdue-tickets?page=${page}&size=5&sort=${sortBy},${sortDirection}`, ); }; export const getTicketStatisticsByTeamId = async (teamId: number) => { return get( - `${BACKEND_API}/api/team-requests/${teamId}/statistics`, + `${BACKEND_API}/api/team-requests/teams/${teamId}/statistics`, ); }; export const getCountOverdueTicketsByTeamId = async (teamId: number) => { return get( - `${BACKEND_API}/api/team-requests/${teamId}/overdue-tickets/count`, + `${BACKEND_API}/api/team-requests/teams/${teamId}/overdue-tickets/count`, ); }; @@ -111,6 +116,25 @@ export const getTicketCreationDaySeries = async ( days: number, ) => { return get( - `${BACKEND_API}/api/team-requests/${teamId}/ticket-creations-day-series?days=${days}`, + `${BACKEND_API}/api/team-requests/teams/${teamId}/ticket-creations-day-series?days=${days}`, + ); +}; + +export const getOverdueTicketsByUser = async ( + userId: number, + page: number, + sortBy: string, + sortDirection: string, +) => { + return get>( + `${BACKEND_API}/api/team-requests/users/${userId}/overdue-tickets?page=${page}&size=5&sort=${sortBy},${sortDirection}`, + ); +}; + +export const getTeamTicketPriorityDistributionForUser = async ( + userId: number, +) => { + return get>( + `${BACKEND_API}/api/team-requests/users/${userId}/team-tickets-priority-distribution`, ); }; diff --git a/src/types/activity-logs.ts b/src/types/activity-logs.ts index 13ae7ff..75b3908 100644 --- a/src/types/activity-logs.ts +++ b/src/types/activity-logs.ts @@ -1,19 +1,13 @@ -import { z } from "zod"; +import { EntityType } from "@/types/commons"; -export const ActivityLogDTOSchema = z.object({ - id: z.number().nullish(), - entityType: z.enum(["Team_Request", "Team"]), - entityId: z.number(), - content: z.string().min(1), - createdAt: z.string().refine((val) => !isNaN(Date.parse(val)), { - message: "Invalid date format", - }), - updatedAt: z.string().refine((val) => !isNaN(Date.parse(val)), { - message: "Invalid date format", - }), - createdById: z.number().nullish(), - createdByName: z.string().nullish(), - createdByImageUrl: z.string().nullish(), -}); - -export type ActivityLogDTO = z.infer; +export interface ActivityLogDTO { + id: number; + entityType: EntityType; + entityName: string; + entityId: number; + content: string; + createdAt: string; // Use ISO string format for Instant + createdById: number; + createdByName: string; + createdByImageUrl: string; +} diff --git a/src/types/teams.ts b/src/types/teams.ts index 9aa470e..3e8b590 100644 --- a/src/types/teams.ts +++ b/src/types/teams.ts @@ -1,5 +1,7 @@ import { z } from "zod"; +import { TeamRequestPriority } from "@/types/team-requests"; + export const TeamDTOSchema = z.object({ id: z.number().nullish(), name: z.string().min(1), @@ -33,3 +35,10 @@ export interface TicketActionCountByDateDTO { createdCount: number; closedCount: number; } + +export interface TeamTicketPriorityDistributionDTO { + teamId: number; + teamName: string; + priority: TeamRequestPriority; + count: number; +}