diff --git a/README.md b/README.md index 9a63d87..364b791 100644 --- a/README.md +++ b/README.md @@ -63,4 +63,3 @@ OKTA_OAUTH2_CLIENT_ID={OKTA APPLICATION CLIENT ID} OKTA_OAUTH2_CLIENT_SECRET={OKTA APPLICATION SECRET} OKTA_OAUTH2_ISSUER=https://{YOUR OKTA ACCOUNT URL (click top right and it will appear below your email)} SECRET=Some long random string - diff --git a/package.json b/package.json index 5250711..21f3c7d 100644 --- a/package.json +++ b/package.json @@ -6,17 +6,28 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "format": "prettier --write ." }, "dependencies": { + "@aws-sdk/client-s3": "^3.513.0", + "@material-tailwind/react": "^2.1.8", "@radix-ui/react-avatar": "^1.0.4", + "@radix-ui/react-checkbox": "^1.0.4", + "@radix-ui/react-collapsible": "^1.0.3", "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-form": "^0.0.3", + "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-menubar": "^1.0.4", "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-scroll-area": "^1.0.5", "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-switch": "^1.0.3", + "@tanstack/react-table": "^8.12.0", "@twilio/voice-sdk": "^2.10.1", + "chart.js": "^4.4.1", + "axios": "^1.6.5", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", "dayjs": "^1.11.10", @@ -25,7 +36,9 @@ "next": "14.0.4", "next-auth": "^4.24.5", "react": "^18", + "react-chartjs-2": "^5.2.0", "react-dom": "^18", + "react-hot-toast": "^2.4.1", "tailwind-merge": "^2.2.0", "tailwindcss-animate": "^1.0.7", "twilio": "^4.20.1", @@ -39,6 +52,7 @@ "eslint": "^8", "eslint-config-next": "14.0.4", "postcss": "^8", + "prettier": "3.2.5", "tailwindcss": "^3.3.0", "typescript": "^5" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 667a84b..0fcffb7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,12 +5,30 @@ settings: excludeLinksFromLockfile: false dependencies: + '@aws-sdk/client-s3': + specifier: ^3.513.0 + version: 3.513.0 + '@material-tailwind/react': + specifier: ^2.1.8 + version: 2.1.8(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-avatar': specifier: ^1.0.4 version: 1.0.4(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-checkbox': + specifier: ^1.0.4 + version: 1.0.4(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-collapsible': + specifier: ^1.0.3 + version: 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-dropdown-menu': specifier: ^2.0.6 version: 2.0.6(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-form': + specifier: ^0.0.3 + version: 0.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-label': + specifier: ^2.0.2 + version: 2.0.2(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-menubar': specifier: ^1.0.4 version: 1.0.4(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) @@ -26,9 +44,21 @@ dependencies: '@radix-ui/react-slot': specifier: ^1.0.2 version: 1.0.2(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-switch': + specifier: ^1.0.3 + version: 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@tanstack/react-table': + specifier: ^8.12.0 + version: 8.12.0(react-dom@18.2.0)(react@18.2.0) '@twilio/voice-sdk': specifier: ^2.10.1 version: 2.10.1 + axios: + specifier: ^1.6.5 + version: 1.6.5 + chart.js: + specifier: ^4.4.1 + version: 4.4.1 class-variance-authority: specifier: ^0.7.0 version: 0.7.0 @@ -53,9 +83,15 @@ dependencies: react: specifier: ^18 version: 18.2.0 + react-chartjs-2: + specifier: ^5.2.0 + version: 5.2.0(chart.js@4.4.1)(react@18.2.0) react-dom: specifier: ^18 version: 18.2.0(react@18.2.0) + react-hot-toast: + specifier: ^2.4.1 + version: 2.4.1(csstype@3.1.3)(react-dom@18.2.0)(react@18.2.0) tailwind-merge: specifier: ^2.2.0 version: 2.2.0 @@ -91,6 +127,9 @@ devDependencies: postcss: specifier: ^8 version: 8.4.32 + prettier: + specifier: 3.2.5 + version: 3.2.5 tailwindcss: specifier: ^3.3.0 version: 3.3.6 @@ -109,12 +148,657 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + /@aws-crypto/crc32@3.0.0: + resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==} + dependencies: + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.511.0 + tslib: 1.14.1 + dev: false + + /@aws-crypto/crc32c@3.0.0: + resolution: {integrity: sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==} + dependencies: + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.511.0 + tslib: 1.14.1 + dev: false + + /@aws-crypto/ie11-detection@3.0.0: + resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} + dependencies: + tslib: 1.14.1 + dev: false + + /@aws-crypto/sha1-browser@3.0.0: + resolution: {integrity: sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==} + dependencies: + '@aws-crypto/ie11-detection': 3.0.0 + '@aws-crypto/supports-web-crypto': 3.0.0 + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.511.0 + '@aws-sdk/util-locate-window': 3.495.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 + dev: false + + /@aws-crypto/sha256-browser@3.0.0: + resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} + dependencies: + '@aws-crypto/ie11-detection': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-crypto/supports-web-crypto': 3.0.0 + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.511.0 + '@aws-sdk/util-locate-window': 3.495.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 + dev: false + + /@aws-crypto/sha256-js@3.0.0: + resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} + dependencies: + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.511.0 + tslib: 1.14.1 + dev: false + + /@aws-crypto/supports-web-crypto@3.0.0: + resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} + dependencies: + tslib: 1.14.1 + dev: false + + /@aws-crypto/util@3.0.0: + resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} + dependencies: + '@aws-sdk/types': 3.511.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 + dev: false + + /@aws-sdk/client-s3@3.513.0: + resolution: {integrity: sha512-Y7kbPLvVVgcn38sTyQP/WnD5Zc7lnJ4XQ8qIPobbkwhCL+rl4hIWcxpQLf1OGS4zw2fBFQAxZnDotuBrAvgNsw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha1-browser': 3.0.0 + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.513.0(@aws-sdk/credential-provider-node@3.513.0) + '@aws-sdk/core': 3.513.0 + '@aws-sdk/credential-provider-node': 3.513.0 + '@aws-sdk/middleware-bucket-endpoint': 3.511.0 + '@aws-sdk/middleware-expect-continue': 3.511.0 + '@aws-sdk/middleware-flexible-checksums': 3.511.0 + '@aws-sdk/middleware-host-header': 3.511.0 + '@aws-sdk/middleware-location-constraint': 3.511.0 + '@aws-sdk/middleware-logger': 3.511.0 + '@aws-sdk/middleware-recursion-detection': 3.511.0 + '@aws-sdk/middleware-sdk-s3': 3.511.0 + '@aws-sdk/middleware-signing': 3.511.0 + '@aws-sdk/middleware-ssec': 3.511.0 + '@aws-sdk/middleware-user-agent': 3.511.0 + '@aws-sdk/region-config-resolver': 3.511.0 + '@aws-sdk/signature-v4-multi-region': 3.511.0 + '@aws-sdk/types': 3.511.0 + '@aws-sdk/util-endpoints': 3.511.0 + '@aws-sdk/util-user-agent-browser': 3.511.0 + '@aws-sdk/util-user-agent-node': 3.511.0 + '@aws-sdk/xml-builder': 3.496.0 + '@smithy/config-resolver': 2.1.1 + '@smithy/core': 1.3.2 + '@smithy/eventstream-serde-browser': 2.1.1 + '@smithy/eventstream-serde-config-resolver': 2.1.1 + '@smithy/eventstream-serde-node': 2.1.1 + '@smithy/fetch-http-handler': 2.4.1 + '@smithy/hash-blob-browser': 2.1.1 + '@smithy/hash-node': 2.1.1 + '@smithy/hash-stream-node': 2.1.1 + '@smithy/invalid-dependency': 2.1.1 + '@smithy/md5-js': 2.1.1 + '@smithy/middleware-content-length': 2.1.1 + '@smithy/middleware-endpoint': 2.4.1 + '@smithy/middleware-retry': 2.1.1 + '@smithy/middleware-serde': 2.1.1 + '@smithy/middleware-stack': 2.1.1 + '@smithy/node-config-provider': 2.2.1 + '@smithy/node-http-handler': 2.3.1 + '@smithy/protocol-http': 3.1.1 + '@smithy/smithy-client': 2.3.1 + '@smithy/types': 2.9.1 + '@smithy/url-parser': 2.1.1 + '@smithy/util-base64': 2.1.1 + '@smithy/util-body-length-browser': 2.1.1 + '@smithy/util-body-length-node': 2.2.1 + '@smithy/util-defaults-mode-browser': 2.1.1 + '@smithy/util-defaults-mode-node': 2.2.0 + '@smithy/util-endpoints': 1.1.1 + '@smithy/util-retry': 2.1.1 + '@smithy/util-stream': 2.1.1 + '@smithy/util-utf8': 2.1.1 + '@smithy/util-waiter': 2.1.1 + fast-xml-parser: 4.2.5 + tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/client-sso-oidc@3.513.0(@aws-sdk/credential-provider-node@3.513.0): + resolution: {integrity: sha512-DyncBVOR5aENL6vOeHPllIAwWUaDZdj1aRKVWiNECG4LuuwwjASX0wFLxTRe/4al3Ugob0OLqsrgC2hd59BLJA==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@aws-sdk/credential-provider-node': ^3.513.0 + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.513.0(@aws-sdk/credential-provider-node@3.513.0) + '@aws-sdk/core': 3.513.0 + '@aws-sdk/credential-provider-node': 3.513.0 + '@aws-sdk/middleware-host-header': 3.511.0 + '@aws-sdk/middleware-logger': 3.511.0 + '@aws-sdk/middleware-recursion-detection': 3.511.0 + '@aws-sdk/middleware-user-agent': 3.511.0 + '@aws-sdk/region-config-resolver': 3.511.0 + '@aws-sdk/types': 3.511.0 + '@aws-sdk/util-endpoints': 3.511.0 + '@aws-sdk/util-user-agent-browser': 3.511.0 + '@aws-sdk/util-user-agent-node': 3.511.0 + '@smithy/config-resolver': 2.1.1 + '@smithy/core': 1.3.2 + '@smithy/fetch-http-handler': 2.4.1 + '@smithy/hash-node': 2.1.1 + '@smithy/invalid-dependency': 2.1.1 + '@smithy/middleware-content-length': 2.1.1 + '@smithy/middleware-endpoint': 2.4.1 + '@smithy/middleware-retry': 2.1.1 + '@smithy/middleware-serde': 2.1.1 + '@smithy/middleware-stack': 2.1.1 + '@smithy/node-config-provider': 2.2.1 + '@smithy/node-http-handler': 2.3.1 + '@smithy/protocol-http': 3.1.1 + '@smithy/smithy-client': 2.3.1 + '@smithy/types': 2.9.1 + '@smithy/url-parser': 2.1.1 + '@smithy/util-base64': 2.1.1 + '@smithy/util-body-length-browser': 2.1.1 + '@smithy/util-body-length-node': 2.2.1 + '@smithy/util-defaults-mode-browser': 2.1.1 + '@smithy/util-defaults-mode-node': 2.2.0 + '@smithy/util-endpoints': 1.1.1 + '@smithy/util-middleware': 2.1.1 + '@smithy/util-retry': 2.1.1 + '@smithy/util-utf8': 2.1.1 + tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/client-sso@3.513.0: + resolution: {integrity: sha512-621Aj/KrgvKJXXViatb3zM+TdM3n+lodmMbSm+FH37RqYoj36s5FgmXan3Ebu9WBu1lUzKm+a3ZyRWVces52uQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/core': 3.513.0 + '@aws-sdk/middleware-host-header': 3.511.0 + '@aws-sdk/middleware-logger': 3.511.0 + '@aws-sdk/middleware-recursion-detection': 3.511.0 + '@aws-sdk/middleware-user-agent': 3.511.0 + '@aws-sdk/region-config-resolver': 3.511.0 + '@aws-sdk/types': 3.511.0 + '@aws-sdk/util-endpoints': 3.511.0 + '@aws-sdk/util-user-agent-browser': 3.511.0 + '@aws-sdk/util-user-agent-node': 3.511.0 + '@smithy/config-resolver': 2.1.1 + '@smithy/core': 1.3.2 + '@smithy/fetch-http-handler': 2.4.1 + '@smithy/hash-node': 2.1.1 + '@smithy/invalid-dependency': 2.1.1 + '@smithy/middleware-content-length': 2.1.1 + '@smithy/middleware-endpoint': 2.4.1 + '@smithy/middleware-retry': 2.1.1 + '@smithy/middleware-serde': 2.1.1 + '@smithy/middleware-stack': 2.1.1 + '@smithy/node-config-provider': 2.2.1 + '@smithy/node-http-handler': 2.3.1 + '@smithy/protocol-http': 3.1.1 + '@smithy/smithy-client': 2.3.1 + '@smithy/types': 2.9.1 + '@smithy/url-parser': 2.1.1 + '@smithy/util-base64': 2.1.1 + '@smithy/util-body-length-browser': 2.1.1 + '@smithy/util-body-length-node': 2.2.1 + '@smithy/util-defaults-mode-browser': 2.1.1 + '@smithy/util-defaults-mode-node': 2.2.0 + '@smithy/util-endpoints': 1.1.1 + '@smithy/util-middleware': 2.1.1 + '@smithy/util-retry': 2.1.1 + '@smithy/util-utf8': 2.1.1 + tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/client-sts@3.513.0(@aws-sdk/credential-provider-node@3.513.0): + resolution: {integrity: sha512-reWhX5CO+XZhT8xIdDPnEws0KQNBuvcSY2W7niSPVYfq1mOLkQgYenP/sC/TyvnNuZDzgcmJQdbdAKHuZvMuUQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@aws-sdk/credential-provider-node': ^3.513.0 + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/core': 3.513.0 + '@aws-sdk/credential-provider-node': 3.513.0 + '@aws-sdk/middleware-host-header': 3.511.0 + '@aws-sdk/middleware-logger': 3.511.0 + '@aws-sdk/middleware-recursion-detection': 3.511.0 + '@aws-sdk/middleware-user-agent': 3.511.0 + '@aws-sdk/region-config-resolver': 3.511.0 + '@aws-sdk/types': 3.511.0 + '@aws-sdk/util-endpoints': 3.511.0 + '@aws-sdk/util-user-agent-browser': 3.511.0 + '@aws-sdk/util-user-agent-node': 3.511.0 + '@smithy/config-resolver': 2.1.1 + '@smithy/core': 1.3.2 + '@smithy/fetch-http-handler': 2.4.1 + '@smithy/hash-node': 2.1.1 + '@smithy/invalid-dependency': 2.1.1 + '@smithy/middleware-content-length': 2.1.1 + '@smithy/middleware-endpoint': 2.4.1 + '@smithy/middleware-retry': 2.1.1 + '@smithy/middleware-serde': 2.1.1 + '@smithy/middleware-stack': 2.1.1 + '@smithy/node-config-provider': 2.2.1 + '@smithy/node-http-handler': 2.3.1 + '@smithy/protocol-http': 3.1.1 + '@smithy/smithy-client': 2.3.1 + '@smithy/types': 2.9.1 + '@smithy/url-parser': 2.1.1 + '@smithy/util-base64': 2.1.1 + '@smithy/util-body-length-browser': 2.1.1 + '@smithy/util-body-length-node': 2.2.1 + '@smithy/util-defaults-mode-browser': 2.1.1 + '@smithy/util-defaults-mode-node': 2.2.0 + '@smithy/util-endpoints': 1.1.1 + '@smithy/util-middleware': 2.1.1 + '@smithy/util-retry': 2.1.1 + '@smithy/util-utf8': 2.1.1 + fast-xml-parser: 4.2.5 + tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/core@3.513.0: + resolution: {integrity: sha512-L+9DL4apWuqNKVOMJ8siAuWoRM9rZf9w1iPv8S2o83WO2jVK7E/m+rNW1dFo9HsA5V1ccDl2H2qLXx24HiHmOw==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/core': 1.3.2 + '@smithy/protocol-http': 3.1.1 + '@smithy/signature-v4': 2.1.1 + '@smithy/smithy-client': 2.3.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/credential-provider-env@3.511.0: + resolution: {integrity: sha512-4VUsnLRox8YzxnZwnFrfZM4bL5KKLhsjjjX7oiuLyzFkhauI4HFYt7rTB8YNGphpqAg/Wzw5DBZfO3Bw1iR1HA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@smithy/property-provider': 2.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/credential-provider-http@3.511.0: + resolution: {integrity: sha512-y83Gt8GPpgMe/lMFxIq+0G2rbzLTC6lhrDocHUzqcApLD6wet8Esy2iYckSRlJgYY+qsVAzpLrSMtt85DwRPTw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@smithy/fetch-http-handler': 2.4.1 + '@smithy/node-http-handler': 2.3.1 + '@smithy/property-provider': 2.1.1 + '@smithy/protocol-http': 3.1.1 + '@smithy/smithy-client': 2.3.1 + '@smithy/types': 2.9.1 + '@smithy/util-stream': 2.1.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/credential-provider-ini@3.513.0(@aws-sdk/credential-provider-node@3.513.0): + resolution: {integrity: sha512-J9FAmTVHm9RsXxXluXCmJ+crkZPDpdNQhiVrbmPPq989lfr0u33rf1aKFMF5AyHNcNEWeAYKKBQwJJkcsxStIA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-sts': 3.513.0(@aws-sdk/credential-provider-node@3.513.0) + '@aws-sdk/credential-provider-env': 3.511.0 + '@aws-sdk/credential-provider-process': 3.511.0 + '@aws-sdk/credential-provider-sso': 3.513.0(@aws-sdk/credential-provider-node@3.513.0) + '@aws-sdk/credential-provider-web-identity': 3.513.0(@aws-sdk/credential-provider-node@3.513.0) + '@aws-sdk/types': 3.511.0 + '@smithy/credential-provider-imds': 2.2.1 + '@smithy/property-provider': 2.1.1 + '@smithy/shared-ini-file-loader': 2.3.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + transitivePeerDependencies: + - '@aws-sdk/credential-provider-node' + - aws-crt + dev: false + + /@aws-sdk/credential-provider-node@3.513.0: + resolution: {integrity: sha512-Cp6tYUJ+g8zJxI8vE0A9W6AxRLq3iR2zGGKsrPLNmZkUaHoVaJiNEd+2nL9RwCqDRve+N+Sh3mbZrLiqh3DO6A==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/credential-provider-env': 3.511.0 + '@aws-sdk/credential-provider-http': 3.511.0 + '@aws-sdk/credential-provider-ini': 3.513.0(@aws-sdk/credential-provider-node@3.513.0) + '@aws-sdk/credential-provider-process': 3.511.0 + '@aws-sdk/credential-provider-sso': 3.513.0(@aws-sdk/credential-provider-node@3.513.0) + '@aws-sdk/credential-provider-web-identity': 3.513.0(@aws-sdk/credential-provider-node@3.513.0) + '@aws-sdk/types': 3.511.0 + '@smithy/credential-provider-imds': 2.2.1 + '@smithy/property-provider': 2.1.1 + '@smithy/shared-ini-file-loader': 2.3.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/credential-provider-process@3.511.0: + resolution: {integrity: sha512-88hLUPqcTwjSubPS+34ZfmglnKeLny8GbmZsyllk96l26PmDTAqo5RScSA8BWxL0l5pRRWGtcrFyts+oibHIuQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@smithy/property-provider': 2.1.1 + '@smithy/shared-ini-file-loader': 2.3.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/credential-provider-sso@3.513.0(@aws-sdk/credential-provider-node@3.513.0): + resolution: {integrity: sha512-q9rRwRWVut97+hnc0Yt77tGeKoPLLDpKKVpVGC6e+EQHlXM4H6oq2VGLgXYJPA9HpMJ3t5zmmgHxEafYeFZo+w==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-sso': 3.513.0 + '@aws-sdk/token-providers': 3.513.0(@aws-sdk/credential-provider-node@3.513.0) + '@aws-sdk/types': 3.511.0 + '@smithy/property-provider': 2.1.1 + '@smithy/shared-ini-file-loader': 2.3.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + transitivePeerDependencies: + - '@aws-sdk/credential-provider-node' + - aws-crt + dev: false + + /@aws-sdk/credential-provider-web-identity@3.513.0(@aws-sdk/credential-provider-node@3.513.0): + resolution: {integrity: sha512-0EZUQhbDaV3jxvIjcWEGiGmioFS0vEvUxaJrMgeRLUo9njZfLZ4VaEMsqPnZ9rMz2w9CxfpDeObEQlDzYeGRgA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-sts': 3.513.0(@aws-sdk/credential-provider-node@3.513.0) + '@aws-sdk/types': 3.511.0 + '@smithy/property-provider': 2.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + transitivePeerDependencies: + - '@aws-sdk/credential-provider-node' + - aws-crt + dev: false + + /@aws-sdk/middleware-bucket-endpoint@3.511.0: + resolution: {integrity: sha512-G4dAAHPUZbpDCVBaCcAOlFoctO9lcecSs0EZYrvzQc/9d4XJvNWGd1C7GSdf204VPOCPZCjNpTkdWGm25r00wA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@aws-sdk/util-arn-parser': 3.495.0 + '@smithy/node-config-provider': 2.2.1 + '@smithy/protocol-http': 3.1.1 + '@smithy/types': 2.9.1 + '@smithy/util-config-provider': 2.2.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/middleware-expect-continue@3.511.0: + resolution: {integrity: sha512-zjDzrJV9PFCkEqhNLKKK+9PB1vPveVZLJbcY71V3PZFvPII1bhlgwvI1e99MhEiaiH2a9I2PnS56bGwEKuNTrw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@smithy/protocol-http': 3.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/middleware-flexible-checksums@3.511.0: + resolution: {integrity: sha512-oI8zULi6VXLXJ3zA6aCdbOoceSNOxGITosB7EKDsLllzAQFV1WlzmQCtjFY8DLLYZ521atgJNcVbzjxPQnrnJA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/crc32': 3.0.0 + '@aws-crypto/crc32c': 3.0.0 + '@aws-sdk/types': 3.511.0 + '@smithy/is-array-buffer': 2.1.1 + '@smithy/protocol-http': 3.1.1 + '@smithy/types': 2.9.1 + '@smithy/util-utf8': 2.1.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/middleware-host-header@3.511.0: + resolution: {integrity: sha512-DbBzQP/6woSHR/+g9dHN3YiYaLIqFw9u8lQFMxi3rT3hqITFVYLzzXtEaHjDD6/is56pNT84CIKbyJ6/gY5d1Q==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@smithy/protocol-http': 3.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/middleware-location-constraint@3.511.0: + resolution: {integrity: sha512-PKHnOT3oBo41NELq3Esz3K9JuV1l9E+SrCcfr/07yU4EbqhS4UGPb22Yf5JakQu4fGbTFlAftcc8PXcE2zLr4g==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/middleware-logger@3.511.0: + resolution: {integrity: sha512-EYU9dBlJXvQcCsM2Tfgi0NQoXrqovfDv/fDy8oGJgZFrgNuHDti8tdVVxeJTUJNEAF67xlDl5o+rWEkKthkYGQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/middleware-recursion-detection@3.511.0: + resolution: {integrity: sha512-PlNPCV/6zpDVdNx1K69xDTh/wPNU4WyP4qa6hUo2/+4/PNG5HI9xbCWtpb4RjhdTRw6qDtkBNcPICHbtWx5aHg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@smithy/protocol-http': 3.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/middleware-sdk-s3@3.511.0: + resolution: {integrity: sha512-SKJr8mKaqjcGpu0xxRPXZiKrJmyetDfgzvWuZ7QOgdnPa+6jk5fmEUTFoPb3VCarMkf8xo/l6cTZ5lei7Lbflw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@aws-sdk/util-arn-parser': 3.495.0 + '@smithy/node-config-provider': 2.2.1 + '@smithy/protocol-http': 3.1.1 + '@smithy/signature-v4': 2.1.1 + '@smithy/smithy-client': 2.3.1 + '@smithy/types': 2.9.1 + '@smithy/util-config-provider': 2.2.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/middleware-signing@3.511.0: + resolution: {integrity: sha512-IMijFLfm+QQHD6NNDX9k3op9dpBSlWKnqjcMU38Tytl2nbqV4gktkarOK1exHAmH7CdoYR5BufVtBzbASNSF/A==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@smithy/property-provider': 2.1.1 + '@smithy/protocol-http': 3.1.1 + '@smithy/signature-v4': 2.1.1 + '@smithy/types': 2.9.1 + '@smithy/util-middleware': 2.1.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/middleware-ssec@3.511.0: + resolution: {integrity: sha512-8pfgBard9pj7oWJ79R6dbXHUGr7JPP/OmAsKBYZA0r/91a1XdFUDtRYZadstjcOv/X3QbeG3QqWOtNco+XgM7Q==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/middleware-user-agent@3.511.0: + resolution: {integrity: sha512-eLs+CxP2QCXh3tCGYCdAml3oyWj8MSIwKbH+8rKw0k/5vmY1YJDBy526whOxx61ivhz2e0muuijN4X5EZZ2Pnw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@aws-sdk/util-endpoints': 3.511.0 + '@smithy/protocol-http': 3.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/region-config-resolver@3.511.0: + resolution: {integrity: sha512-RzBLSNaRd4iEkQyEGfiSNvSnWU/x23rsiFgA9tqYFA0Vqx7YmzSWC8QBUxpwybB8HkbbL9wNVKQqTbhI3mYneQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@smithy/node-config-provider': 2.2.1 + '@smithy/types': 2.9.1 + '@smithy/util-config-provider': 2.2.1 + '@smithy/util-middleware': 2.1.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/signature-v4-multi-region@3.511.0: + resolution: {integrity: sha512-lwbU3LX5TpYu1DHBMH2Wz+2MWGccn5G3psu1Y9WTPc+1bubVQHWf8UD2lzON5L2QirT9tQheQjTke1u5JC7FTQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/middleware-sdk-s3': 3.511.0 + '@aws-sdk/types': 3.511.0 + '@smithy/protocol-http': 3.1.1 + '@smithy/signature-v4': 2.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/token-providers@3.513.0(@aws-sdk/credential-provider-node@3.513.0): + resolution: {integrity: sha512-S27iFzj3dVRw1q+xLtqTGZOfYG95OwvTN7crvS2daqSYfcWN+dhEPzQJdDvGaAnAI45bWm8rppH/EYzrlxeZoA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-sso-oidc': 3.513.0(@aws-sdk/credential-provider-node@3.513.0) + '@aws-sdk/types': 3.511.0 + '@smithy/property-provider': 2.1.1 + '@smithy/shared-ini-file-loader': 2.3.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + transitivePeerDependencies: + - '@aws-sdk/credential-provider-node' + - aws-crt + dev: false + + /@aws-sdk/types@3.511.0: + resolution: {integrity: sha512-P03ufufxmkvd7nO46oOeEqYIMPJ8qMCKxAsfJk1JBVPQ1XctVntbail4/UFnrnzij8DTl4Mk/D62uGo7+RolXA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/util-arn-parser@3.495.0: + resolution: {integrity: sha512-hwdA3XAippSEUxs7jpznwD63YYFR+LtQvlEcebPTgWR9oQgG9TfS+39PUfbnEeje1ICuOrN3lrFqFbmP9uzbMg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.6.2 + dev: false + + /@aws-sdk/util-endpoints@3.511.0: + resolution: {integrity: sha512-J/5hsscJkg2pAOdLx1YKlyMCk5lFRxRxEtup9xipzOxVBlqOIE72Tuu31fbxSlF8XzO/AuCJcZL4m1v098K9oA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.511.0 + '@smithy/types': 2.9.1 + '@smithy/util-endpoints': 1.1.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/util-locate-window@3.495.0: + resolution: {integrity: sha512-MfaPXT0kLX2tQaR90saBT9fWQq2DHqSSJRzW+MZWsmF+y5LGCOhO22ac/2o6TKSQm7h0HRc2GaADqYYYor62yg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.6.2 + dev: false + + /@aws-sdk/util-user-agent-browser@3.511.0: + resolution: {integrity: sha512-5LuESdwtIcA10aHcX7pde7aCIijcyTPBXFuXmFlDTgm/naAayQxelQDpvgbzuzGLgePf8eTyyhDKhzwPZ2EqiQ==} + dependencies: + '@aws-sdk/types': 3.511.0 + '@smithy/types': 2.9.1 + bowser: 2.11.0 + tslib: 2.6.2 + dev: false + + /@aws-sdk/util-user-agent-node@3.511.0: + resolution: {integrity: sha512-UopdlRvYY5mxlS4wwFv+QAWL6/T302wmoQj7i+RY+c/D3Ej3PKBb/mW3r2wEOgZLJmPpeeM1SYMk+rVmsW1rqw==} + engines: {node: '>=14.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + dependencies: + '@aws-sdk/types': 3.511.0 + '@smithy/node-config-provider': 2.2.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@aws-sdk/util-utf8-browser@3.259.0: + resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} + dependencies: + tslib: 2.6.2 + dev: false + + /@aws-sdk/xml-builder@3.496.0: + resolution: {integrity: sha512-GvEjh537IIeOw1ZkZuB37sV12u+ipS5Z1dwjEC/HAvhl5ac23ULtTr1/n+U1gLNN+BAKSWjKiQ2ksj8DiUzeyw==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + /@babel/runtime@7.23.5: resolution: {integrity: sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.0 + /@emotion/is-prop-valid@0.8.8: + resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==} + requiresBuild: true + dependencies: + '@emotion/memoize': 0.7.4 + dev: false + optional: true + + /@emotion/memoize@0.7.4: + resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==} + requiresBuild: true + dev: false + optional: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.55.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -165,6 +849,17 @@ packages: '@floating-ui/utils': 0.1.6 dev: false + /@floating-ui/react-dom@1.3.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-htwHm67Ji5E/pROEAr7f8IKFShuiCKHwUC/UY4vC3I5jiSvGFAYnSYiZO5MlGmads+QqvUkR9ANHEguGrDv72g==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@floating-ui/dom': 1.5.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@floating-ui/react-dom@2.0.4(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==} peerDependencies: @@ -176,6 +871,19 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@floating-ui/react@0.19.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-fgYvN4ksCi5OvmPXkyOT8o5a8PSKHMzPHt+9mR6KYWdF16IAjWRLZPAAziI2sznaWT23drRFrYw64wdvYqqaQw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@floating-ui/react-dom': 1.3.0(react-dom@18.2.0)(react@18.2.0) + aria-hidden: 1.2.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + tabbable: 6.2.0 + dev: false + /@floating-ui/utils@0.1.6: resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} dev: false @@ -225,24 +933,92 @@ packages: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 - /@next/env@14.0.4: - resolution: {integrity: sha512-irQnbMLbUNQpP1wcE5NstJtbuA/69kRfzBrpAD7Gsn8zm/CY6YQYc3HQBz8QPxwISG26tIm5afvvVbu508oBeQ==} + /@kurkle/color@0.3.2: + resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==} dev: false - /@next/eslint-plugin-next@14.0.4: - resolution: {integrity: sha512-U3qMNHmEZoVmHA0j/57nRfi3AscXNvkOnxDmle/69Jz/G0o/gWjXTDdlgILZdrxQ0Lw/jv2mPW8PGy0EGIHXhQ==} - dependencies: - glob: 7.1.7 - dev: true - - /@next/swc-darwin-arm64@14.0.4: - resolution: {integrity: sha512-mF05E/5uPthWzyYDyptcwHptucf/jj09i2SXBPwNzbgBNc+XnwzrL0U6BmPjQeOL+FiB+iG1gwBeq7mlDjSRPg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - requiresBuild: true + /@material-tailwind/react@2.1.8(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-+YI8DTS8dz8FNkjbsgz1HS6+CRszZ+gUErw5FnTuAL2ONeM9R204B6u4PKd9otjYlQQS/fKjKuQ/mwLubWljfg==} + peerDependencies: + react: ^16 || ^17 || ^18 + react-dom: ^16 || ^17 || ^18 + dependencies: + '@floating-ui/react': 0.19.0(react-dom@18.2.0)(react@18.2.0) + classnames: 2.3.2 + deepmerge: 4.2.2 + framer-motion: 6.5.1(react-dom@18.2.0)(react@18.2.0) + material-ripple-effects: 2.0.1 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + tailwind-merge: 1.8.1 dev: false - optional: true + + /@motionone/animation@10.17.0: + resolution: {integrity: sha512-ANfIN9+iq1kGgsZxs+Nz96uiNcPLGTXwfNo2Xz/fcJXniPYpaz/Uyrfa+7I5BPLxCP82sh7quVDudf1GABqHbg==} + dependencies: + '@motionone/easing': 10.17.0 + '@motionone/types': 10.17.0 + '@motionone/utils': 10.17.0 + tslib: 2.6.2 + dev: false + + /@motionone/dom@10.12.0: + resolution: {integrity: sha512-UdPTtLMAktHiqV0atOczNYyDd/d8Cf5fFsd1tua03PqTwwCe/6lwhLSQ8a7TbnQ5SN0gm44N1slBfj+ORIhrqw==} + dependencies: + '@motionone/animation': 10.17.0 + '@motionone/generators': 10.17.0 + '@motionone/types': 10.17.0 + '@motionone/utils': 10.17.0 + hey-listen: 1.0.8 + tslib: 2.6.2 + dev: false + + /@motionone/easing@10.17.0: + resolution: {integrity: sha512-Bxe2wSuLu/qxqW4rBFS5m9tMLOw+QBh8v5A7Z5k4Ul4sTj5jAOfZG5R0bn5ywmk+Fs92Ij1feZ5pmC4TeXA8Tg==} + dependencies: + '@motionone/utils': 10.17.0 + tslib: 2.6.2 + dev: false + + /@motionone/generators@10.17.0: + resolution: {integrity: sha512-T6Uo5bDHrZWhIfxG/2Aut7qyWQyJIWehk6OB4qNvr/jwA/SRmixwbd7SOrxZi1z5rH3LIeFFBKK1xHnSbGPZSQ==} + dependencies: + '@motionone/types': 10.17.0 + '@motionone/utils': 10.17.0 + tslib: 2.6.2 + dev: false + + /@motionone/types@10.17.0: + resolution: {integrity: sha512-EgeeqOZVdRUTEHq95Z3t8Rsirc7chN5xFAPMYFobx8TPubkEfRSm5xihmMUkbaR2ErKJTUw3347QDPTHIW12IA==} + dev: false + + /@motionone/utils@10.17.0: + resolution: {integrity: sha512-bGwrki4896apMWIj9yp5rAS2m0xyhxblg6gTB/leWDPt+pb410W8lYWsxyurX+DH+gO1zsQsfx2su/c1/LtTpg==} + dependencies: + '@motionone/types': 10.17.0 + hey-listen: 1.0.8 + tslib: 2.6.2 + dev: false + + /@next/env@14.0.4: + resolution: {integrity: sha512-irQnbMLbUNQpP1wcE5NstJtbuA/69kRfzBrpAD7Gsn8zm/CY6YQYc3HQBz8QPxwISG26tIm5afvvVbu508oBeQ==} + dev: false + + /@next/eslint-plugin-next@14.0.4: + resolution: {integrity: sha512-U3qMNHmEZoVmHA0j/57nRfi3AscXNvkOnxDmle/69Jz/G0o/gWjXTDdlgILZdrxQ0Lw/jv2mPW8PGy0EGIHXhQ==} + dependencies: + glob: 7.1.7 + dev: true + + /@next/swc-darwin-arm64@14.0.4: + resolution: {integrity: sha512-mF05E/5uPthWzyYDyptcwHptucf/jj09i2SXBPwNzbgBNc+XnwzrL0U6BmPjQeOL+FiB+iG1gwBeq7mlDjSRPg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true /@next/swc-darwin-x64@14.0.4: resolution: {integrity: sha512-IZQ3C7Bx0k2rYtrZZxKKiusMTM9WWcK5ajyhOZkYYTCc8xytmwSzR1skU7qLgVT/EY9xtXDG0WhY6fyujnI3rw==} @@ -336,7 +1112,8 @@ packages: /@panva/hkdf@1.1.1: resolution: {integrity: sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==} - + dev: false + /@radix-ui/number@1.0.1: resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} dependencies: @@ -394,6 +1171,62 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-checkbox@1.0.4(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@types/react': 18.2.42 + '@types/react-dom': 18.2.17 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-collapsible@1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@types/react': 18.2.42 + '@types/react-dom': 18.2.17 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} peerDependencies: @@ -549,6 +1382,32 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-form@0.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-kgE+Z/haV6fxE5WqIXj05KkaXa3OkZASoTDy25yX2EIp/x0c54rOH/vFr5nOZTg7n7T1z8bSyXmiVIFP9bbhPQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-label': 2.0.2(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.42 + '@types/react-dom': 18.2.17 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-id@1.0.1(@types/react@18.2.42)(react@18.2.0): resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} peerDependencies: @@ -564,6 +1423,27 @@ packages: react: 18.2.0 dev: false + /@radix-ui/react-label@2.0.2(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.42 + '@types/react-dom': 18.2.17 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-menu@2.0.6(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA==} peerDependencies: @@ -774,184 +1654,680 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.5 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@radix-ui/react-id': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@types/react': 18.2.42 - '@types/react-dom': 18.2.17 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@babel/runtime': 7.23.5 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@types/react': 18.2.42 + '@types/react-dom': 18.2.17 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-scroll-area@1.0.5(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-b6PAgH4GQf9QEn8zbT2XUHpW5z8BzqEc7Kl11TwDrvuTrxlkcjTD5qa/bxgKr+nmuXKu4L/W5UZ4mlP/VG/5Gw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/number': 1.0.1 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@types/react': 18.2.42 + '@types/react-dom': 18.2.17 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-separator@1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.42 + '@types/react-dom': 18.2.17 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-slot@1.0.2(@types/react@18.2.42)(react@18.2.0): + resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@types/react': 18.2.42 + react: 18.2.0 + dev: false + + /@radix-ui/react-switch@1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-mxm87F88HyHztsI7N+ZUmEoARGkC22YVW5CaC+Byc+HRpuvCrOBPTAnXgf+tZ/7i0Sg/eOePGdMhUKhPaQEqow==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@types/react': 18.2.42 + '@types/react-dom': 18.2.17 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.42)(react@18.2.0): + resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@types/react': 18.2.42 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.42)(react@18.2.0): + resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@types/react': 18.2.42 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.42)(react@18.2.0): + resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@types/react': 18.2.42 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.42)(react@18.2.0): + resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@types/react': 18.2.42 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-previous@1.0.1(@types/react@18.2.42)(react@18.2.0): + resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@types/react': 18.2.42 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.42)(react@18.2.0): + resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/rect': 1.0.1 + '@types/react': 18.2.42 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-size@1.0.1(@types/react@18.2.42)(react@18.2.0): + resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.42)(react@18.2.0) + '@types/react': 18.2.42 + react: 18.2.0 + dev: false + + /@radix-ui/rect@1.0.1: + resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} + dependencies: + '@babel/runtime': 7.23.5 + dev: false + + /@rushstack/eslint-patch@1.6.0: + resolution: {integrity: sha512-2/U3GXA6YiPYQDLGwtGlnNgKYBSwCFIHf8Y9LUY5VATHdtbLlU0Y1R3QoBnT0aB4qv/BEiVVsj7LJXoQCgJ2vA==} + dev: true + + /@smithy/abort-controller@2.1.1: + resolution: {integrity: sha512-1+qdrUqLhaALYL0iOcN43EP6yAXXQ2wWZ6taf4S2pNGowmOc5gx+iMQv+E42JizNJjB0+gEadOXeV1Bf7JWL1Q==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/chunked-blob-reader-native@2.1.1: + resolution: {integrity: sha512-zNW+43dltfNMUrBEYLMWgI8lQr0uhtTcUyxkgC9EP4j17WREzgSFMPUFVrVV6Rc2+QtWERYjb4tzZnQGa7R9fQ==} + dependencies: + '@smithy/util-base64': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/chunked-blob-reader@2.1.1: + resolution: {integrity: sha512-NjNFCKxC4jVvn+lUr3Yo4/PmUJj3tbyqH6GNHueyTGS5Q27vlEJ1MkNhUDV8QGxJI7Bodnc2pD18lU2zRfhHlQ==} + dependencies: + tslib: 2.6.2 + dev: false + + /@smithy/config-resolver@2.1.1: + resolution: {integrity: sha512-lxfLDpZm+AWAHPFZps5JfDoO9Ux1764fOgvRUBpHIO8HWHcSN1dkgsago1qLRVgm1BZ8RCm8cgv99QvtaOWIhw==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/node-config-provider': 2.2.1 + '@smithy/types': 2.9.1 + '@smithy/util-config-provider': 2.2.1 + '@smithy/util-middleware': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/core@1.3.2: + resolution: {integrity: sha512-tYDmTp0f2TZVE18jAOH1PnmkngLQ+dOGUlMd1u67s87ieueNeyqhja6z/Z4MxhybEiXKOWFOmGjfTZWFxljwJw==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/middleware-endpoint': 2.4.1 + '@smithy/middleware-retry': 2.1.1 + '@smithy/middleware-serde': 2.1.1 + '@smithy/protocol-http': 3.1.1 + '@smithy/smithy-client': 2.3.1 + '@smithy/types': 2.9.1 + '@smithy/util-middleware': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/credential-provider-imds@2.2.1: + resolution: {integrity: sha512-7XHjZUxmZYnONheVQL7j5zvZXga+EWNgwEAP6OPZTi7l8J4JTeNh9aIOfE5fKHZ/ee2IeNOh54ZrSna+Vc6TFA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/node-config-provider': 2.2.1 + '@smithy/property-provider': 2.1.1 + '@smithy/types': 2.9.1 + '@smithy/url-parser': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/eventstream-codec@2.1.1: + resolution: {integrity: sha512-E8KYBxBIuU4c+zrpR22VsVrOPoEDzk35bQR3E+xm4k6Pa6JqzkDOdMyf9Atac5GPNKHJBdVaQ4JtjdWX2rl/nw==} + dependencies: + '@aws-crypto/crc32': 3.0.0 + '@smithy/types': 2.9.1 + '@smithy/util-hex-encoding': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/eventstream-serde-browser@2.1.1: + resolution: {integrity: sha512-JvEdCmGlZUay5VtlT8/kdR6FlvqTDUiJecMjXsBb0+k1H/qc9ME5n2XKPo8q/MZwEIA1GmGgYMokKGjVvMiDow==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/eventstream-serde-universal': 2.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/eventstream-serde-config-resolver@2.1.1: + resolution: {integrity: sha512-EqNqXYp3+dk//NmW3NAgQr9bEQ7fsu/CcxQmTiq07JlaIcne/CBWpMZETyXm9w5LXkhduBsdXdlMscfDUDn2fA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/eventstream-serde-node@2.1.1: + resolution: {integrity: sha512-LF882q/aFidFNDX7uROAGxq3H0B7rjyPkV6QDn6/KDQ+CG7AFkRccjxRf1xqajq/Pe4bMGGr+VKAaoF6lELIQw==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/eventstream-serde-universal': 2.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/eventstream-serde-universal@2.1.1: + resolution: {integrity: sha512-LR0mMT+XIYTxk4k2fIxEA1BPtW3685QlqufUEUAX1AJcfFfxNDKEvuCRZbO8ntJb10DrIFVJR9vb0MhDCi0sAQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/eventstream-codec': 2.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/fetch-http-handler@2.4.1: + resolution: {integrity: sha512-VYGLinPsFqH68lxfRhjQaSkjXM7JysUOJDTNjHBuN/ykyRb2f1gyavN9+VhhPTWCy32L4yZ2fdhpCs/nStEicg==} + dependencies: + '@smithy/protocol-http': 3.1.1 + '@smithy/querystring-builder': 2.1.1 + '@smithy/types': 2.9.1 + '@smithy/util-base64': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/hash-blob-browser@2.1.1: + resolution: {integrity: sha512-jizu1+2PAUjiGIfRtlPEU8Yo6zn+d78ti/ZHDesdf1SUn2BuZW433JlPoCOLH3dBoEEvTgLvQ8tUGSoTTALA+A==} + dependencies: + '@smithy/chunked-blob-reader': 2.1.1 + '@smithy/chunked-blob-reader-native': 2.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/hash-node@2.1.1: + resolution: {integrity: sha512-Qhoq0N8f2OtCnvUpCf+g1vSyhYQrZjhSwvJ9qvR8BUGOtTXiyv2x1OD2e6jVGmlpC4E4ax1USHoyGfV9JFsACg==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.9.1 + '@smithy/util-buffer-from': 2.1.1 + '@smithy/util-utf8': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/hash-stream-node@2.1.1: + resolution: {integrity: sha512-VgDaKcfCy0iHcmtAZgZ3Yw9g37Gkn2JsQiMtFQXUh8Wmo3GfNgDwLOtdhJ272pOT7DStzpe9cNr+eV5Au8KfQA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.9.1 + '@smithy/util-utf8': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/invalid-dependency@2.1.1: + resolution: {integrity: sha512-7WTgnKw+VPg8fxu2v9AlNOQ5yaz6RA54zOVB4f6vQuR0xFKd+RzlCpt0WidYTsye7F+FYDIaS/RnJW4pxjNInw==} + dependencies: + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/is-array-buffer@2.1.1: + resolution: {integrity: sha512-xozSQrcUinPpNPNPds4S7z/FakDTh1MZWtRP/2vQtYB/u3HYrX2UXuZs+VhaKBd6Vc7g2XPr2ZtwGBNDN6fNKQ==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.6.2 + dev: false + + /@smithy/md5-js@2.1.1: + resolution: {integrity: sha512-L3MbIYBIdLlT+MWTYrdVSv/dow1+6iZ1Ad7xS0OHxTTs17d753ZcpOV4Ro7M7tRAVWML/sg2IAp/zzCb6aAttg==} + dependencies: + '@smithy/types': 2.9.1 + '@smithy/util-utf8': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/middleware-content-length@2.1.1: + resolution: {integrity: sha512-rSr9ezUl9qMgiJR0UVtVOGEZElMdGFyl8FzWEF5iEKTlcWxGr2wTqGfDwtH3LAB7h+FPkxqv4ZU4cpuCN9Kf/g==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/protocol-http': 3.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/middleware-endpoint@2.4.1: + resolution: {integrity: sha512-XPZTb1E2Oav60Ven3n2PFx+rX9EDsU/jSTA8VDamt7FXks67ekjPY/XrmmPDQaFJOTUHJNKjd8+kZxVO5Ael4Q==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/middleware-serde': 2.1.1 + '@smithy/node-config-provider': 2.2.1 + '@smithy/shared-ini-file-loader': 2.3.1 + '@smithy/types': 2.9.1 + '@smithy/url-parser': 2.1.1 + '@smithy/util-middleware': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/middleware-retry@2.1.1: + resolution: {integrity: sha512-eMIHOBTXro6JZ+WWzZWd/8fS8ht5nS5KDQjzhNMHNRcG5FkNTqcKpYhw7TETMYzbLfhO5FYghHy1vqDWM4FLDA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/node-config-provider': 2.2.1 + '@smithy/protocol-http': 3.1.1 + '@smithy/service-error-classification': 2.1.1 + '@smithy/smithy-client': 2.3.1 + '@smithy/types': 2.9.1 + '@smithy/util-middleware': 2.1.1 + '@smithy/util-retry': 2.1.1 + tslib: 2.6.2 + uuid: 8.3.2 + dev: false + + /@smithy/middleware-serde@2.1.1: + resolution: {integrity: sha512-D8Gq0aQBeE1pxf3cjWVkRr2W54t+cdM2zx78tNrVhqrDykRA7asq8yVJij1u5NDtKzKqzBSPYh7iW0svUKg76g==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/middleware-stack@2.1.1: + resolution: {integrity: sha512-KPJhRlhsl8CjgGXK/DoDcrFGfAqoqvuwlbxy+uOO4g2Azn1dhH+GVfC3RAp+6PoL5PWPb+vt6Z23FP+Mr6qeCw==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/node-config-provider@2.2.1: + resolution: {integrity: sha512-epzK3x1xNxA9oJgHQ5nz+2j6DsJKdHfieb+YgJ7ATWxzNcB7Hc+Uya2TUck5MicOPhDV8HZImND7ZOecVr+OWg==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/property-provider': 2.1.1 + '@smithy/shared-ini-file-loader': 2.3.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/node-http-handler@2.3.1: + resolution: {integrity: sha512-gLA8qK2nL9J0Rk/WEZSvgin4AppvuCYRYg61dcUo/uKxvMZsMInL5I5ZdJTogOvdfVug3N2dgI5ffcUfS4S9PA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/abort-controller': 2.1.1 + '@smithy/protocol-http': 3.1.1 + '@smithy/querystring-builder': 2.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/property-provider@2.1.1: + resolution: {integrity: sha512-FX7JhhD/o5HwSwg6GLK9zxrMUrGnb3PzNBrcthqHKBc3dH0UfgEAU24xnJ8F0uow5mj17UeBEOI6o3CF2k7Mhw==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/protocol-http@3.1.1: + resolution: {integrity: sha512-6ZRTSsaXuSL9++qEwH851hJjUA0OgXdQFCs+VDw4tGH256jQ3TjYY/i34N4vd24RV3nrjNsgd1yhb57uMoKbzQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/querystring-builder@2.1.1: + resolution: {integrity: sha512-C/ko/CeEa8jdYE4gt6nHO5XDrlSJ3vdCG0ZAc6nD5ZIE7LBp0jCx4qoqp7eoutBu7VrGMXERSRoPqwi1WjCPbg==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.9.1 + '@smithy/util-uri-escape': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/querystring-parser@2.1.1: + resolution: {integrity: sha512-H4+6jKGVhG1W4CIxfBaSsbm98lOO88tpDWmZLgkJpt8Zkk/+uG0FmmqMuCAc3HNM2ZDV+JbErxr0l5BcuIf/XQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/service-error-classification@2.1.1: + resolution: {integrity: sha512-txEdZxPUgM1PwGvDvHzqhXisrc5LlRWYCf2yyHfvITWioAKat7srQvpjMAvgzf0t6t7j8yHrryXU9xt7RZqFpw==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.9.1 + dev: false + + /@smithy/shared-ini-file-loader@2.3.1: + resolution: {integrity: sha512-2E2kh24igmIznHLB6H05Na4OgIEilRu0oQpYXo3LCNRrawHAcfDKq9004zJs+sAMt2X5AbY87CUCJ7IpqpSgdw==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/signature-v4@2.1.1: + resolution: {integrity: sha512-Hb7xub0NHuvvQD3YwDSdanBmYukoEkhqBjqoxo+bSdC0ryV9cTfgmNjuAQhTPYB6yeU7hTR+sPRiFMlxqv6kmg==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/eventstream-codec': 2.1.1 + '@smithy/is-array-buffer': 2.1.1 + '@smithy/types': 2.9.1 + '@smithy/util-hex-encoding': 2.1.1 + '@smithy/util-middleware': 2.1.1 + '@smithy/util-uri-escape': 2.1.1 + '@smithy/util-utf8': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/smithy-client@2.3.1: + resolution: {integrity: sha512-YsTdU8xVD64r2pLEwmltrNvZV6XIAC50LN6ivDopdt+YiF/jGH6PY9zUOu0CXD/d8GMB8gbhnpPsdrjAXHS9QA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/middleware-endpoint': 2.4.1 + '@smithy/middleware-stack': 2.1.1 + '@smithy/protocol-http': 3.1.1 + '@smithy/types': 2.9.1 + '@smithy/util-stream': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/types@2.9.1: + resolution: {integrity: sha512-vjXlKNXyprDYDuJ7UW5iobdmyDm6g8dDG+BFUncAg/3XJaN45Gy5RWWWUVgrzIK7S4R1KWgIX5LeJcfvSI24bw==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.6.2 + dev: false + + /@smithy/url-parser@2.1.1: + resolution: {integrity: sha512-qC9Bv8f/vvFIEkHsiNrUKYNl8uKQnn4BdhXl7VzQRP774AwIjiSMMwkbT+L7Fk8W8rzYVifzJNYxv1HwvfBo3Q==} + dependencies: + '@smithy/querystring-parser': 2.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false + + /@smithy/util-base64@2.1.1: + resolution: {integrity: sha512-UfHVpY7qfF/MrgndI5PexSKVTxSZIdz9InghTFa49QOvuu9I52zLPLUHXvHpNuMb1iD2vmc6R+zbv/bdMipR/g==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/util-buffer-from': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/util-body-length-browser@2.1.1: + resolution: {integrity: sha512-ekOGBLvs1VS2d1zM2ER4JEeBWAvIOUKeaFch29UjjJsxmZ/f0L3K3x0dEETgh3Q9bkZNHgT+rkdl/J/VUqSRag==} + dependencies: + tslib: 2.6.2 + dev: false + + /@smithy/util-body-length-node@2.2.1: + resolution: {integrity: sha512-/ggJG+ta3IDtpNVq4ktmEUtOkH1LW64RHB5B0hcr5ZaWBmo96UX2cIOVbjCqqDickTXqBWZ4ZO0APuaPrD7Abg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.6.2 dev: false - /@radix-ui/react-scroll-area@1.0.5(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-b6PAgH4GQf9QEn8zbT2XUHpW5z8BzqEc7Kl11TwDrvuTrxlkcjTD5qa/bxgKr+nmuXKu4L/W5UZ4mlP/VG/5Gw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + /@smithy/util-buffer-from@2.1.1: + resolution: {integrity: sha512-clhNjbyfqIv9Md2Mg6FffGVrJxw7bgK7s3Iax36xnfVj6cg0fUG7I4RH0XgXJF8bxi+saY5HR21g2UPKSxVCXg==} + engines: {node: '>=14.0.0'} dependencies: - '@babel/runtime': 7.23.5 - '@radix-ui/number': 1.0.1 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@types/react': 18.2.42 - '@types/react-dom': 18.2.17 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@smithy/is-array-buffer': 2.1.1 + tslib: 2.6.2 dev: false - /@radix-ui/react-separator@1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + /@smithy/util-config-provider@2.2.1: + resolution: {integrity: sha512-50VL/tx9oYYcjJn/qKqNy7sCtpD0+s8XEBamIFo4mFFTclKMNp+rsnymD796uybjiIquB7VCB/DeafduL0y2kw==} + engines: {node: '>=14.0.0'} dependencies: - '@babel/runtime': 7.23.5 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.42 - '@types/react-dom': 18.2.17 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + tslib: 2.6.2 dev: false - /@radix-ui/react-slot@1.0.2(@types/react@18.2.42)(react@18.2.0): - resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + /@smithy/util-defaults-mode-browser@2.1.1: + resolution: {integrity: sha512-lqLz/9aWRO6mosnXkArtRuQqqZBhNpgI65YDpww4rVQBuUT7qzKbDLG5AmnQTCiU4rOquaZO/Kt0J7q9Uic7MA==} + engines: {node: '>= 10.0.0'} dependencies: - '@babel/runtime': 7.23.5 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@types/react': 18.2.42 - react: 18.2.0 + '@smithy/property-provider': 2.1.1 + '@smithy/smithy-client': 2.3.1 + '@smithy/types': 2.9.1 + bowser: 2.11.0 + tslib: 2.6.2 dev: false - /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.42)(react@18.2.0): - resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + /@smithy/util-defaults-mode-node@2.2.0: + resolution: {integrity: sha512-iFJp/N4EtkanFpBUtSrrIbtOIBf69KNuve03ic1afhJ9/korDxdM0c6cCH4Ehj/smI9pDCfVv+bqT3xZjF2WaA==} + engines: {node: '>= 10.0.0'} dependencies: - '@babel/runtime': 7.23.5 - '@types/react': 18.2.42 - react: 18.2.0 + '@smithy/config-resolver': 2.1.1 + '@smithy/credential-provider-imds': 2.2.1 + '@smithy/node-config-provider': 2.2.1 + '@smithy/property-provider': 2.1.1 + '@smithy/smithy-client': 2.3.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 dev: false - /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.42)(react@18.2.0): - resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + /@smithy/util-endpoints@1.1.1: + resolution: {integrity: sha512-sI4d9rjoaekSGEtq3xSb2nMjHMx8QXcz2cexnVyRWsy4yQ9z3kbDpX+7fN0jnbdOp0b3KSTZJZ2Yb92JWSanLw==} + engines: {node: '>= 14.0.0'} dependencies: - '@babel/runtime': 7.23.5 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@types/react': 18.2.42 - react: 18.2.0 + '@smithy/node-config-provider': 2.2.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 dev: false - /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.42)(react@18.2.0): - resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + /@smithy/util-hex-encoding@2.1.1: + resolution: {integrity: sha512-3UNdP2pkYUUBGEXzQI9ODTDK+Tcu1BlCyDBaRHwyxhA+8xLP8agEKQq4MGmpjqb4VQAjq9TwlCQX0kP6XDKYLg==} + engines: {node: '>=14.0.0'} dependencies: - '@babel/runtime': 7.23.5 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@types/react': 18.2.42 - react: 18.2.0 + tslib: 2.6.2 dev: false - /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.42)(react@18.2.0): - resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + /@smithy/util-middleware@2.1.1: + resolution: {integrity: sha512-mKNrk8oz5zqkNcbcgAAepeJbmfUW6ogrT2Z2gDbIUzVzNAHKJQTYmH9jcy0jbWb+m7ubrvXKb6uMjkSgAqqsFA==} + engines: {node: '>=14.0.0'} dependencies: - '@babel/runtime': 7.23.5 - '@types/react': 18.2.42 - react: 18.2.0 + '@smithy/types': 2.9.1 + tslib: 2.6.2 dev: false - /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.42)(react@18.2.0): - resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + /@smithy/util-retry@2.1.1: + resolution: {integrity: sha512-Mg+xxWPTeSPrthpC5WAamJ6PW4Kbo01Fm7lWM1jmGRvmrRdsd3192Gz2fBXAMURyXpaNxyZf6Hr/nQ4q70oVEA==} + engines: {node: '>= 14.0.0'} dependencies: - '@babel/runtime': 7.23.5 - '@radix-ui/rect': 1.0.1 - '@types/react': 18.2.42 - react: 18.2.0 + '@smithy/service-error-classification': 2.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 dev: false - /@radix-ui/react-use-size@1.0.1(@types/react@18.2.42)(react@18.2.0): - resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + /@smithy/util-stream@2.1.1: + resolution: {integrity: sha512-J7SMIpUYvU4DQN55KmBtvaMc7NM3CZ2iWICdcgaovtLzseVhAqFRYqloT3mh0esrFw+3VEK6nQFteFsTqZSECQ==} + engines: {node: '>=14.0.0'} dependencies: - '@babel/runtime': 7.23.5 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.42)(react@18.2.0) - '@types/react': 18.2.42 - react: 18.2.0 + '@smithy/fetch-http-handler': 2.4.1 + '@smithy/node-http-handler': 2.3.1 + '@smithy/types': 2.9.1 + '@smithy/util-base64': 2.1.1 + '@smithy/util-buffer-from': 2.1.1 + '@smithy/util-hex-encoding': 2.1.1 + '@smithy/util-utf8': 2.1.1 + tslib: 2.6.2 dev: false - /@radix-ui/rect@1.0.1: - resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} + /@smithy/util-uri-escape@2.1.1: + resolution: {integrity: sha512-saVzI1h6iRBUVSqtnlOnc9ssU09ypo7n+shdQ8hBTZno/9rZ3AuRYvoHInV57VF7Qn7B+pFJG7qTzFiHxWlWBw==} + engines: {node: '>=14.0.0'} dependencies: - '@babel/runtime': 7.23.5 + tslib: 2.6.2 dev: false - /@rushstack/eslint-patch@1.6.0: - resolution: {integrity: sha512-2/U3GXA6YiPYQDLGwtGlnNgKYBSwCFIHf8Y9LUY5VATHdtbLlU0Y1R3QoBnT0aB4qv/BEiVVsj7LJXoQCgJ2vA==} - dev: true + /@smithy/util-utf8@2.1.1: + resolution: {integrity: sha512-BqTpzYEcUMDwAKr7/mVRUtHDhs6ZoXDi9NypMvMfOr/+u1NW7JgqodPDECiiLboEm6bobcPcECxzjtQh865e9A==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/util-buffer-from': 2.1.1 + tslib: 2.6.2 + dev: false + + /@smithy/util-waiter@2.1.1: + resolution: {integrity: sha512-kYy6BLJJNif+uqNENtJqWdXcpqo1LS+nj1AfXcDhOpqpSHJSAkVySLyZV9fkmuVO21lzGoxjvd1imGGJHph/IA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/abort-controller': 2.1.1 + '@smithy/types': 2.9.1 + tslib: 2.6.2 + dev: false /@swc/helpers@0.5.2: resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} @@ -959,6 +2335,23 @@ packages: tslib: 2.6.2 dev: false + /@tanstack/react-table@8.12.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-LlEQ1Gpz4bfpiET+qmle4BhKDgKN3Y/sssc+O/wLqX8HRtjV+nhusYbllZlutZfMR8oeef83whKTj/VhaV8EeA==} + engines: {node: '>=12'} + peerDependencies: + react: '>=16' + react-dom: '>=16' + dependencies: + '@tanstack/table-core': 8.12.0 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@tanstack/table-core@8.12.0: + resolution: {integrity: sha512-cq/ylWVrOwixmwNXQjgZaQw1Izf7+nPxjczum7paAnMtwPg1S2qRAJU+Jb8rEBUWm69voC/zcChmePlk2hc6ug==} + engines: {node: '>=12'} + dev: false + /@twilio/voice-errors@1.4.0: resolution: {integrity: sha512-7BCg9MPz+KQ0JJ6Rl5W3Zw3E+i3Tt77VZw3/2i3Z+IPZITmCOQLu1nKx/0Nlj505Xtfr7eY9Mcern5PfIoBW0w==} dev: false @@ -1287,6 +2680,10 @@ packages: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} + /bowser@2.11.0: + resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + dev: false + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -1352,6 +2749,13 @@ packages: resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} dev: false + /chart.js@4.4.1: + resolution: {integrity: sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==} + engines: {pnpm: '>=7'} + dependencies: + '@kurkle/color': 0.3.2 + dev: false + /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -1372,6 +2776,10 @@ packages: clsx: 2.0.0 dev: false + /classnames@2.3.2: + resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==} + dev: false + /client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} dev: false @@ -1466,6 +2874,11 @@ packages: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true + /deepmerge@4.2.2: + resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} + engines: {node: '>=0.10.0'} + dev: false + /define-data-property@1.1.1: resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} engines: {node: '>= 0.4'} @@ -1946,6 +3359,13 @@ packages: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true + /fast-xml-parser@4.2.5: + resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==} + hasBin: true + dependencies: + strnum: 1.0.5 + dev: false + /fastq@1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: @@ -2013,6 +3433,30 @@ packages: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} dev: true + /framer-motion@6.5.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==} + peerDependencies: + react: '>=16.8 || ^17.0.0 || ^18.0.0' + react-dom: '>=16.8 || ^17.0.0 || ^18.0.0' + dependencies: + '@motionone/dom': 10.12.0 + framesync: 6.0.1 + hey-listen: 1.0.8 + popmotion: 11.0.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + style-value-types: 5.0.0 + tslib: 2.6.2 + optionalDependencies: + '@emotion/is-prop-valid': 0.8.8 + dev: false + + /framesync@6.0.1: + resolution: {integrity: sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==} + dependencies: + tslib: 2.6.2 + dev: false + /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -2141,6 +3585,14 @@ packages: slash: 3.0.0 dev: true + /goober@2.1.14(csstype@3.1.3): + resolution: {integrity: sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==} + peerDependencies: + csstype: ^3.0.10 + dependencies: + csstype: 3.1.3 + dev: false + /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: @@ -2187,6 +3639,10 @@ packages: dependencies: function-bind: 1.1.2 + /hey-listen@1.0.8: + resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} + dev: false + /https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} @@ -2617,6 +4073,10 @@ packages: resolution: {integrity: sha512-aioqzx9hgnYzm7HhNAZR7lHd32zlnJlIweo1JxCf9xXGEEj90f05RMhaq1tY5nz20WUW7ZFOZ9sXVvlv3zs0Iw==} dev: false + /material-ripple-effects@2.0.1: + resolution: {integrity: sha512-hHlUkZAuXbP94lu02VgrPidbZ3hBtgXBtjlwR8APNqOIgDZMV8MCIcsclL8FmGJQHvnORyvoQgC965vPsiyXLQ==} + dev: false + /md5@2.3.0: resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} dependencies: @@ -2928,6 +4388,15 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + /popmotion@11.0.3: + resolution: {integrity: sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==} + dependencies: + framesync: 6.0.1 + hey-listen: 1.0.8 + style-value-types: 5.0.0 + tslib: 2.6.2 + dev: false + /postcss-import@15.1.0(postcss@8.4.32): resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} @@ -3018,6 +4487,12 @@ packages: engines: {node: '>= 0.8.0'} dev: true + /prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + engines: {node: '>=14'} + hasBin: true + dev: true + /pretty-format@3.8.0: resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==} dev: false @@ -3028,7 +4503,6 @@ packages: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 - dev: true /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -3053,6 +4527,16 @@ packages: /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + /react-chartjs-2@5.2.0(chart.js@4.4.1)(react@18.2.0): + resolution: {integrity: sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==} + peerDependencies: + chart.js: ^4.1.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + chart.js: 4.4.1 + react: 18.2.0 + dev: false + /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: @@ -3063,9 +4547,22 @@ packages: scheduler: 0.23.0 dev: false + /react-hot-toast@2.4.1(csstype@3.1.3)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==} + engines: {node: '>=10'} + peerDependencies: + react: '>=16' + react-dom: '>=16' + dependencies: + goober: 2.1.14(csstype@3.1.3) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + transitivePeerDependencies: + - csstype + dev: false + /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - dev: true /react-remove-scroll-bar@2.3.4(@types/react@18.2.42)(react@18.2.0): resolution: {integrity: sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==} @@ -3377,6 +4874,17 @@ packages: engines: {node: '>=8'} dev: true + /strnum@1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + dev: false + + /style-value-types@5.0.0: + resolution: {integrity: sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==} + dependencies: + hey-listen: 1.0.8 + tslib: 2.6.2 + dev: false + /styled-jsx@5.1.1(react@18.2.0): resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} @@ -3418,6 +4926,14 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + /tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + dev: false + + /tailwind-merge@1.8.1: + resolution: {integrity: sha512-+fflfPxvHFr81hTJpQ3MIwtqgvefHZFUHFiIHpVIRXvG/nX9+gu2P7JNlFu2bfDMJ+uHhi/pUgzaYacMoXv+Ww==} + dev: false + /tailwind-merge@2.2.0: resolution: {integrity: sha512-SqqhhaL0T06SW59+JVNfAqKdqLs0497esifRrZ7jOaefP3o64fdFNDMrAQWZFMxTLJPiHVjRLUywT8uFz1xNWQ==} dependencies: @@ -3509,6 +5025,10 @@ packages: strip-bom: 3.0.0 dev: true + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: false + /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} dev: false diff --git a/src/app/api/agent/route.ts b/src/app/api/agent/route.ts new file mode 100644 index 0000000..a15ae33 --- /dev/null +++ b/src/app/api/agent/route.ts @@ -0,0 +1,31 @@ +import { NextResponse, NextRequest } from "next/server"; + +interface Activity { + sid: string; +} + +export async function POST(request: NextRequest) { + const accountSid = process.env.TWILIO_ACCOUNT_SID; + const authToken = process.env.TWILIO_AUTH_TOKEN; + const workspaceSid = process.env.TWILIO_TASKROUTER_WORKSPACE_SID; + //Need to update via Okta authentification + const workerSid = process.env.TWILIO_WORKER_SID; + const client = require("twilio")(accountSid, authToken); + + const body = await request.json(); + const { activitySid } = body; + + try { + const worker = await client.taskrouter.v1 + .workspaces(workspaceSid) + .workers(workerSid) + .update({ + activitySid, + }); + + console.log(worker.activityName); + return NextResponse.json(worker.activityName); + } catch (error) { + console.error("Failed to update worker:", error); + } +} diff --git a/src/app/api/audit-log/calls/route.ts b/src/app/api/audit-log/calls/route.ts new file mode 100644 index 0000000..bb7624a --- /dev/null +++ b/src/app/api/audit-log/calls/route.ts @@ -0,0 +1,44 @@ + +import {NextResponse, NextRequest} from 'next/server'; +import { formatDate } from '@/lib/utils'; + + +interface Calls { + id: string; + direction: string; + from: string | null; + to: string | null; + timestamp: string; +} + +export async function GET( + request: NextRequest, + res: NextResponse +) { + const accountSid = process.env.TWILIO_ACCOUNT_SID; + const authToken = process.env.TWILIO_AUTH_TOKEN; + const client = require('twilio')(accountSid, authToken); + try{ + const calls: any[] = await client.calls.list({limit:20}); + //if want to display all calls, can delete the limit parameter + const formattedCalls: Calls[] = calls.map(call => { + const date = new Date(call.dateCreated); + const formattedDate = formatDate(date, 'YYYY-MM-DD HH:mm') + return { + id: call.sid, + from: call.from, + to: call.to, + direction: call.direction, + timestamp: formattedDate // Use the formatted date string + }; + }); + return NextResponse.json(formattedCalls) + + } catch (error) { + console.error('Error fetching call logs', error); + } + +} + +export const dynamic = 'force-dynamic' + diff --git a/src/app/api/audit-log/message/route.ts b/src/app/api/audit-log/message/route.ts new file mode 100644 index 0000000..18eae20 --- /dev/null +++ b/src/app/api/audit-log/message/route.ts @@ -0,0 +1,46 @@ + +import {NextResponse, NextRequest} from 'next/server'; +import { formatDate } from '@/lib/utils'; + +interface Message { + id: string; + from: string; + to: string; + direction: string; + timestamp: string; +} + +export async function GET( + request: NextRequest, + res: NextResponse +) { + const accountSid = process.env.TWILIO_ACCOUNT_SID; + const authToken = process.env.TWILIO_AUTH_TOKEN; + const client = require('twilio')(accountSid, authToken); + try{ + const messages: any[] = await client.messages.list({limit:20}); + //if want to display all calls, can delete the limit parameter + const formattedMessages: Message[] = messages.map(message => { + const date = new Date(message.dateCreated); + const formattedDate = formatDate(date, 'YYYY-MM-DD HH:mm') + return{ + id: message.sid, + direction: message.direction, + from: message.from, + to: message.to, + timestamp: formattedDate + } + + + }) + + // console.log(formattedMessages) + return NextResponse.json(formattedMessages) + + } catch (error) { + console.error('Error fetching message logs', error); + } + +} + +export const dynamic = 'force-dynamic' \ No newline at end of file diff --git a/src/app/api/crm_example/route.ts b/src/app/api/crm_example/route.ts index 635996b..411c3cd 100644 --- a/src/app/api/crm_example/route.ts +++ b/src/app/api/crm_example/route.ts @@ -1,10 +1,9 @@ -import { AirtableCRMProvider } from "../../../lib/crm/airtable"; - - +import { AirtableCRMProvider, s3KeyForAirtableToken, s3KeyForAirtableBase, s3KeyForAirtableTable } from "../../../lib/crm/airtable"; +import { authOptions } from "@/lib/auth"; +import { getObjectString } from "@/lib/aws/s3"; +import { getServerSession } from "next-auth/next"; +import { NextRequest} from "next/server"; // ENV variables for now, pending CRM configuration feature -const AIRTABLE_TEST_API_KEY = process.env.AIRTABLE_TEST_API_KEY || ""; -const AIRTABLE_TEST_BASE_ID = process.env.AIRTABLE_TEST_BASE_ID || ""; -const AIRTABLE_TEST_TABLE_ID = process.env.AIRTABLE_TEST_TABLE_ID || ""; /** @@ -12,19 +11,36 @@ const AIRTABLE_TEST_TABLE_ID = process.env.AIRTABLE_TEST_TABLE_ID || ""; * * @param request - The incoming request object. * @returns A JSON response with the client info. - */ -export async function GET(request: Request) { - const provider = new AirtableCRMProvider(AIRTABLE_TEST_BASE_ID, AIRTABLE_TEST_API_KEY); +*/ +export async function GET(request: NextRequest) { + const session = await getServerSession(authOptions) as any; + if (!session) { + return new Response('Unauthorized', { status: 401 }); + } + + const oktaId = session.oktaId; + + const [airtable_token, airtable_base_id, airtable_table_id] = await Promise.all([ + getObjectString(s3KeyForAirtableToken(oktaId)), + getObjectString(s3KeyForAirtableBase(oktaId)), + getObjectString(s3KeyForAirtableTable(oktaId)) + ]); - const table = provider.getTable(AIRTABLE_TEST_TABLE_ID); + console.log(airtable_token, airtable_base_id, airtable_table_id) + + const provider = new AirtableCRMProvider(airtable_base_id, airtable_token); + + const table = provider.getTable(airtable_table_id); const url = new URL(request.url); - const queryParams = new URLSearchParams(url.search); - const phone: string = queryParams.get("phone") || "1234567890"; + // const queryParams = new URLSearchParams(url.search); + // const phone: string = queryParams.get("phone") || "1234567890"; + + // const clientInfo = await table.getClientByPhone(phone); - const clientInfo = await table.getClientByPhone(phone); + const allClients = await table.getAllRows(); - return new Response(JSON.stringify(clientInfo), { + return new Response(JSON.stringify(allClients), { headers: { "content-type": "application/json", }, diff --git a/src/app/api/crmconfig/airtable/route.ts b/src/app/api/crmconfig/airtable/route.ts new file mode 100644 index 0000000..69d63e6 --- /dev/null +++ b/src/app/api/crmconfig/airtable/route.ts @@ -0,0 +1,46 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { getServerSession } from "next-auth/next"; +import { putObject, getObjectString } from '../../../../lib/aws/s3'; +import { authOptions } from '@/lib/auth'; +import { NextRequest, NextResponse } from 'next/server'; +import { s3KeyForAirtableBase, s3KeyForAirtableTable, s3KeyForAirtableToken } from '@/lib/crm/airtable'; + +type AirtableTokenData = { + token: string; + baseId: string; + tableId: string; +}; + +export async function POST(req: NextRequest) { + const session = await getServerSession(authOptions) as any; + + + const res = NextResponse.next(); + if (!session) { + return new Response('Unauthorized', { status: 401 }); + } + + const oktaId = session.oktaId; + const body = await req.json() as AirtableTokenData; + const token = body.token; + const baseId = body.baseId; + const tableId = body.tableId; + + try { + const tokenKey = s3KeyForAirtableToken(oktaId); + const baseIdKey = s3KeyForAirtableBase(oktaId); + const tableIdKey = s3KeyForAirtableTable(oktaId); + + await Promise.all([ + putObject(tokenKey, token), + putObject(baseIdKey, baseId), + putObject(tableIdKey, tableId) + ]); + + + return new Response('Success', { status: 200 }); + } catch (error) { + console.error(error); + return new Response('Put in S3 unsuccessful: ' + error, { status: 500 }); + } +}; \ No newline at end of file diff --git a/src/app/dashboard/(program-manager)/billings/page.tsx b/src/app/dashboard/(program-manager)/billings/page.tsx index a78404e..700d2bf 100644 --- a/src/app/dashboard/(program-manager)/billings/page.tsx +++ b/src/app/dashboard/(program-manager)/billings/page.tsx @@ -1,7 +1,182 @@ +"use client"; +import React, { useState } from "react"; +import { Line } from "react-chartjs-2"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend, +} from "chart.js"; +import { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, +} from "@/components/ui/dropdown-menu"; + +ChartJS.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend, +); + +interface BillingPeriod { + startDate: string; + endDate: string; + id: string; +} + +interface UsageStatistics { + callsPlaced: number[]; + messagesSent: number[]; +} + +// Sample data for billing periods and usage statistics +const billingPeriods: BillingPeriod[] = [ + { startDate: "January 12", endDate: "February 12", id: "jan-feb" }, + { startDate: "February 13", endDate: "March 13", id: "feb-mar" }, + { startDate: "March 14", endDate: "April 14", id: "mar-apr" }, + // Add more billing periods as needed +]; + +const usageData: { [key: string]: UsageStatistics } = { + "jan-feb": { + callsPlaced: [50, 75, 150, 125, 200, 220], + messagesSent: [400, 600, 900, 800, 1300, 1600], + }, + "feb-mar": { + callsPlaced: [60, 80, 100, 150, 180, 200], + messagesSent: [500, 700, 800, 950, 1100, 1200], + }, + "mar-apr": { + callsPlaced: [70, 90, 110, 130, 160, 190], + messagesSent: [450, 650, 850, 1000, 1150, 1300], + }, + // Add more usage statistics keyed by billing period id +}; + export default function Billings() { + const [selectedBillingPeriod, setSelectedBillingPeriod] = useState( + billingPeriods[0].id, + ); + + const getChartData = () => { + const data = usageData[selectedBillingPeriod]; + const period = billingPeriods.find( + (period) => period.id === selectedBillingPeriod, + ); + if (!period) return { labels: [], datasets: [] }; // Return empty data if no period is found + + const startDate = new Date(period.startDate); + const endDate = new Date(period.endDate); + const differenceInTime = endDate.getTime() - startDate.getTime(); + const differenceInDays = differenceInTime / (1000 * 3600 * 24); + + // Calculate the interval in days between the points + const interval = differenceInDays / (data.callsPlaced.length - 1); + + const labels = data.callsPlaced.map((_, index) => { + const date = new Date( + startDate.getTime() + interval * index * 1000 * 3600 * 24, + ); + return date.toLocaleDateString("en-US", { + month: "short", + day: "numeric", + }); + }); + return { + labels: labels, + datasets: [ + { + label: "Calls Placed", + data: data.callsPlaced, + borderColor: "rgb(53, 162, 235)", + backgroundColor: "rgba(53, 162, 235, 0.5)", + }, + { + label: "Messages Sent", + data: data.messagesSent, + borderColor: "#e08500", + backgroundColor: "#FF9500", + }, + ], + }; + }; + return ( -
-

Billings

+
+
+

Billings and Usage

+

+ Understand your organization’s Connie usage here. +

+
+ +
+

Current Balance

+

$240.89

+
+ +
+ + + + + + + {billingPeriods.map((period) => ( + setSelectedBillingPeriod(period.id)} + > + {`${period.startDate} - ${period.endDate}`} + + ))} + + +
+ +
+

Usage Breakdown

+
+ +
+
+
+

Calls placed

+

+ {usageData[selectedBillingPeriod].callsPlaced.at(-1)} +

+
+
+

Messages sent

+

+ {usageData[selectedBillingPeriod].messagesSent.at(-1)} +

+
+
+
+
); } + +//chart values hard-coded for example purposes diff --git a/src/app/dashboard/Home.css b/src/app/dashboard/Home.css new file mode 100644 index 0000000..6833940 --- /dev/null +++ b/src/app/dashboard/Home.css @@ -0,0 +1,33 @@ +.step-oval::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 100%; /* Adjust width as needed */ + height: 45px; /* Adjust height as needed */ + border-radius: 30px; + border: 2px solid #E2E8F0; /* Adjust color as needed */ + transform: translate(-50%, -50%); + z-index: 0; +} + +.step-oval.active::before { + border-color: #FF9500; /* Adjust for active step */ +} + +.step-oval.completed::before { + border-color: #FF9500; /* Adjust for completed step */ +} + +.step-checkmark::after { + content: '\2714'; /* Unicode checkmark */ + color: #FF9500; /* Adjust checkmark color as needed */ + font-size: 18px; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 1; +} + + diff --git a/src/app/dashboard/clients/[client]/page.tsx b/src/app/dashboard/clients/[client]/page.tsx index 378ca9d..bfba1fc 100644 --- a/src/app/dashboard/clients/[client]/page.tsx +++ b/src/app/dashboard/clients/[client]/page.tsx @@ -5,7 +5,7 @@ import { Button } from "@/components/ui/button"; // TODO check if user exists -export default function Client({ params }: { params: { client: string } }) { +export default function ClientPage({ params }: { params: { client: string } }) { const [openNotes, setOpenNotes] = useState(false); return (
diff --git a/src/app/dashboard/clients/page.tsx b/src/app/dashboard/clients/page.tsx index cd5068e..6d03450 100644 --- a/src/app/dashboard/clients/page.tsx +++ b/src/app/dashboard/clients/page.tsx @@ -1,7 +1,18 @@ -export default function Clients() { +import { ClientTable } from "@/components/clientTable/ClientTable"; +import { columns } from "@/components/clientTable/columns"; +import { CRMEntry } from "@/lib/crm/types"; +import fetchClients from "@/lib/data/clients"; + +export default async function ClientsPage() { + const data: CRMEntry[] = await fetchClients(); + return ( -
-
All clients
+
+

Clients

+

+ Browse and search for all client contacts here. +

+
); } diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index da358f5..93febf3 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -1,14 +1,103 @@ -"use client" -import IncomingCallModal from "@/components/(dashboard)/tasks/IncomingCallModal"; -import NotificationsCard from "@/components/appbar/NotificationsCard"; - -export default function Dashboard() { - return ( -
-

Dashboard

- {/* {}} rejectCall={() => {}} /> */} - {/* */} -
- ); - } - \ No newline at end of file +'use client'; + +import React, { useState } from 'react'; +import './Home.css'; + + +const steps = [ + "Dashboard Cards", + "Notifications", + "Communicate With Clients", + "Change Status" +]; + + +export default function DashboardHome() { + const [currentPage, setCurrentPage] = useState(0); + const [completedSteps, setCompletedSteps] = useState(new Array(steps.length).fill(false)); + // const tutorialCompleted = localStorage.getItem('tutorialCompleted') === 'true'; + // const [showPopup, setShowPopup] = useState(!tutorialCompleted); + const [showPopup, setShowPopup] = useState(true); + const [showFinishButton, setShowFinishButton] = useState(false); + + + const goToNextPage = () => { + const newCompletedSteps = [...completedSteps]; + newCompletedSteps[currentPage] = true; + setCompletedSteps(newCompletedSteps); + if (currentPage < steps.length - 1) { + setCurrentPage(currentPage + 1); + } else { + setShowFinishButton(true); + } + }; + + + const finishTutorial = () => { + // Set the last step as completed before closing + const newCompletedSteps = [...completedSteps]; + newCompletedSteps[currentPage] = true; + setCompletedSteps(newCompletedSteps); + // localStorage.setItem('tutorialCompleted', 'true'); + setShowPopup(false); + }; + + + return ( +
+ {showPopup && ( +
+ +
+

Welcome to Connie.

+

We’re so happy you’re here. Get to know your space through a few simple steps. Here are the main functions of your dashboard:

+
+ +
+
+ {steps.map((step, index) => ( +
+
+
+ ))} +
+ + +
+ {steps.map((step, index) => ( +
+
+
{step}
+
+ ))} +
+
+ {steps.map((content, index) => ( +
+ {`Content for ${content}`} +
+ ))} +
+
+
+ {!showFinishButton ? ( + + ) : ( + + )} +
+
+ )} +
+ ); +} diff --git a/src/app/dashboard/settings/org/audit-log/page.tsx b/src/app/dashboard/settings/org/audit-log/page.tsx new file mode 100644 index 0000000..f6c503e --- /dev/null +++ b/src/app/dashboard/settings/org/audit-log/page.tsx @@ -0,0 +1,20 @@ +import AuditTable from "@/components/audittable/AuditTable"; +import { Button } from "@/components/ui/button"; + + +export default function AuditLog() { + + return ( +
+

Audit Log

+

+ View all calls and SMS message your organization made via Connie. +

+
+ +
+ +
+
+ ); + } \ No newline at end of file diff --git a/src/app/dashboard/settings/page.tsx b/src/app/dashboard/settings/page.tsx index 86c3bb9..c62ab7a 100644 --- a/src/app/dashboard/settings/page.tsx +++ b/src/app/dashboard/settings/page.tsx @@ -1,7 +1,56 @@ -export default function Settings() { - return ( -
-

Settings

-
- ); -} +'use client'; + +import React from 'react'; +import SingleForm from '@/components/ui/single-form'; + +const Page = () => { + const AIRTABLE_TOKEN_STR = "Airtable Token"; + const AIRTABLE_BASE_ID_STR = "Airtable Base ID"; + const AIRTABLE_TABLE_ID_STR = "Airtable Table ID"; + + const onSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + const formData = new FormData(event.currentTarget); + const airtableToken = formData.get(AIRTABLE_TOKEN_STR); + const airtableBaseId = formData.get(AIRTABLE_BASE_ID_STR); + const airtableTableId = formData.get(AIRTABLE_TABLE_ID_STR); + + try { + const response = await fetch('../api/crmconfig/airtable', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ token: airtableToken, + baseId: airtableBaseId, + tableId: airtableTableId + }), + }); + // Handle the response + } catch (error) { + // Handle the error + } + }; + + const fields = [{ + name: AIRTABLE_TOKEN_STR, + label: AIRTABLE_TOKEN_STR, + }, + { + name: AIRTABLE_BASE_ID_STR, + label: AIRTABLE_BASE_ID_STR, + }, + { + name: AIRTABLE_TABLE_ID_STR, + label: AIRTABLE_TABLE_ID_STR, + }]; + + + return ( +
+ +
+ ); +}; + +export default Page; diff --git a/src/app/page.tsx b/src/app/page.tsx index 20e3960..1a07f78 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,10 +1,11 @@ "use client"; + import { useSession } from 'next-auth/react'; import React from 'react'; import { redirect } from 'next/navigation' export default function Home() { - const {data: session, status} = useSession(); + const { data: session, status } = useSession(); if (status === 'loading') { return Loading...; } else if (session) { @@ -12,4 +13,4 @@ export default function Home() { } else { redirect('/login'); } -} +} \ No newline at end of file diff --git a/src/components/ClientOnly.tsx b/src/components/ClientOnly.tsx new file mode 100644 index 0000000..bbebad2 --- /dev/null +++ b/src/components/ClientOnly.tsx @@ -0,0 +1,23 @@ +"use client"; + +import { useEffect, useState } from "react"; + +interface ClientOnlyProps { + children: React.ReactNode; +} + +const ClientOnly: React.FC = ({ children }) => { + const [hasMounted, setHasMounted] = useState(false); + + useEffect(() => { + setHasMounted(true); + }, []); + + if (!hasMounted) { + return null; + } + + return <>{children}; +}; + +export default ClientOnly; diff --git a/src/components/appbar/AgentStatus.tsx b/src/components/appbar/AgentStatus.tsx new file mode 100644 index 0000000..bedb569 --- /dev/null +++ b/src/components/appbar/AgentStatus.tsx @@ -0,0 +1,78 @@ +"use client"; + +import React, { useState } from "react"; +import { Chip } from "@material-tailwind/react"; +import { Button } from "../ui/button"; + +import axios from "axios"; + +//Need to change based on every single diff. Taskrouter workspace +const activities = { + Available: "", + Unavailable: "", + Offline: "", +}; + +const AgentStatus: React.FC = () => { + const [activity, setActivity] = useState("Unavailable"); + + const toggleAvailability = async () => { + const newActivity = + activity === "Unavailable" ? "Available" : "Unavailable"; + setActivity(newActivity); + const activitySid = activities[newActivity]; + + //Request to API route + try { + // Send a request to your API route using axios + const response = await axios.post("/api/agent", { + activitySid, + }); + } catch (error) { + console.error("Error updating status:", error); + // If API call fail, make no change + setActivity(activity); + } + }; + + return ( +
+ +
+
Status
+ +
+ {activity === "Available" ? ( + <> + + } + /> + + ) : ( + <> + + } + /> + + )} +
+
+
+ ); +}; + +export default AgentStatus; diff --git a/src/components/appbar/index.tsx b/src/components/appbar/index.tsx index be0d319..c50730b 100644 --- a/src/components/appbar/index.tsx +++ b/src/components/appbar/index.tsx @@ -40,6 +40,9 @@ import useCalls from "@/lib/hooks/useCalls"; import { useSession } from "next-auth/react"; import IncomingCallModal from "../(dashboard)/tasks/IncomingCallModal"; +import AgentStatus from "./AgentStatus"; +import ClientOnly from "../ClientOnly"; + interface AppbarProps extends React.HTMLAttributes { initials: string; isProgramManager: boolean; // TODO replace with proper authorization check @@ -76,8 +79,12 @@ export default function Appbar({
{/* TODO replace with Availability status toggle component */} -
(Status)
-
+
+ + + +
+
+ +
+
+
+ + +
+
+ + +
+
+ + +
+ + +
+ + ); +} + +export default AuditTable; \ No newline at end of file diff --git a/src/components/audittable/DataTable.tsx b/src/components/audittable/DataTable.tsx new file mode 100644 index 0000000..d2bb705 --- /dev/null +++ b/src/components/audittable/DataTable.tsx @@ -0,0 +1,114 @@ +"use client" + +import { + ColumnDef, + flexRender, + getCoreRowModel, + getPaginationRowModel, + useReactTable, +} from "@tanstack/react-table" + +import {Button} from "@/components/ui/button" + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" + +import React, {useState} from 'react' + +interface DataTableProps { + columns: ColumnDef[] + data: TData[] +} + +export function DataTable({ + columns, + data, +}: DataTableProps) { + + const [rowSelection, setRowSelection] = useState({}) + + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + onRowSelectionChange: setRowSelection, + state: { + rowSelection + } + }) + + + return ( +
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ) + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+
+ + +
+
+ ) +} diff --git a/src/components/audittable/columns.tsx b/src/components/audittable/columns.tsx new file mode 100644 index 0000000..3d09607 --- /dev/null +++ b/src/components/audittable/columns.tsx @@ -0,0 +1,97 @@ +"use client" + +import { ColumnDef } from "@tanstack/react-table" +import { MoreHorizontal } from "lucide-react" +import {Checkbox} from "@/components/ui/checkbox" + +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" + + +// This type is used to define the shape of our data. +export type FetchedCalls = { + id: string; + direction: string; + from: string | null; + to: string | null; + timestamp: string; +} + +export const columns: ColumnDef[] = [ + { + id: "select", + header: ({ table }) => ( + table.toggleAllPageRowsSelected(!!value)} + aria-label="Select all" + /> + ), + cell: ({ row }) => ( + row.toggleSelected(!!value)} + aria-label="Select row" + /> + ), + enableSorting: false, + enableHiding: false, + }, + + { + accessorKey: "direction", + header: "Direction", + }, + { + accessorKey: "from", + header: "From", + }, + { + accessorKey: "to", + header: "To", + }, + + { + accessorKey: "timestamp", + header: "Timestamp", + }, + + { + id: "actions", + cell: ({ row }) => { + const call = row.original + + return ( + + + + + + Actions + navigator.clipboard.writeText(call.id)} + > + Export + + + View details + + + ) + }, + }, + +] diff --git a/src/components/clientTable/ClientTable.tsx b/src/components/clientTable/ClientTable.tsx new file mode 100644 index 0000000..56e4b5d --- /dev/null +++ b/src/components/clientTable/ClientTable.tsx @@ -0,0 +1,156 @@ +"use client"; +import { useState } from "react"; +import { useSession } from "next-auth/react"; + +import { + ColumnDef, + flexRender, + getCoreRowModel, + getFilteredRowModel, + useReactTable, + getPaginationRowModel, +} from "@tanstack/react-table"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Separator } from "@/components/ui/separator"; + +import { copyText } from "@/lib/utils"; +import useCalls from "@/lib/hooks/useCalls"; +import { CRMEntry } from "@/lib/crm/types"; + +interface DataTableProps { + columns: ColumnDef[]; + data: CRMEntry[]; +} + +export function ClientTable({ columns, data }: DataTableProps) { + const [globalFilter, setGlobalFilter] = useState(""); + const { data: session } = useSession(); + + const { makeCall } = useCalls({ + email: session?.user?.email ?? "", + workerSid: "WK3b277b4e6a1d67f2240477fa33f75ea4", // TODO link twilio worker id with okta + friendlyName: session?.user?.name ?? "", + }); + + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + onGlobalFilterChange: setGlobalFilter, + getFilteredRowModel: getFilteredRowModel(), + state: { + globalFilter, + }, + meta: { + onPhoneNumberCopy: (number: string) => { + copyText(number); + }, + onMakeCall: (number: string) => { + makeCall(number); + }, + }, + }); + + const rows = table.getRowModel().rows; + + return ( +
+
+
+
+ + setGlobalFilter(String(e.target.value))} + /> +
+

+ {data.length} clients synced from CRM +

+ +
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ); + })} + + ))} + + + {rows?.length ? ( + rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+
+
+ + +
+
+ ); +} diff --git a/src/components/clientTable/columns.tsx b/src/components/clientTable/columns.tsx new file mode 100644 index 0000000..ae1ca6d --- /dev/null +++ b/src/components/clientTable/columns.tsx @@ -0,0 +1,100 @@ +"use client"; +import Link from "next/link"; + +import { ColumnDef } from "@tanstack/react-table"; +import { Checkbox } from "@/components/ui/checkbox"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Button } from "@/components/ui/button"; +import { MoreVertical } from "lucide-react"; +import { CRMEntry } from "@/lib/crm/types"; + +export const columns: ColumnDef[] = [ + { + id: "select", + header: ({ table }) => ( + table.toggleAllPageRowsSelected(!!value)} + aria-label="Select all" + /> + ), + cell: ({ row }) => ( + row.toggleSelected(!!value)} + aria-label="Select row" + /> + ), + enableSorting: false, + enableHiding: false, + }, + { + header: () =>

Id

, + accessorKey: "id", + }, + { + accessorKey: "full_name", + header: () =>

Client

, + }, + { + accessorKey: "Phone", + header: () =>

Phone Number

, + }, + { + accessorKey: "email", + header: () =>

Email

, + }, + { + accessorKey: "lastContacted", + header: () =>

Last contacted

, + }, + { + id: "actions", + enableHiding: false, + cell: ({ row, table }) => { + const client = row.original; + return ( + + + + + + Actions + {/* + (table.options.meta as any)?.onMakeCall(client.Phone) + } + > + Call + */} + + (table.options.meta as any)?.onPhoneNumberCopy(client.Phone) + } + > + Copy phone number + + + + See more details + + + + + ); + }, + }, +]; diff --git a/src/components/notes/index.tsx b/src/components/notes/index.tsx index 82ef85e..aa929d2 100644 --- a/src/components/notes/index.tsx +++ b/src/components/notes/index.tsx @@ -1,5 +1,6 @@ "use client"; import { useState, useEffect, ChangeEvent } from "react"; +import { useSession } from "next-auth/react"; import dayjs from "dayjs"; import { Button } from "@/components/ui/button"; @@ -21,6 +22,8 @@ export default function Notes({ clientId }: { clientId: string }) { const [newNote, setNewNote] = useState(""); + const { data: session } = useSession(); + useEffect(() => { const fetchNotes = async () => { setLoading(true); @@ -48,7 +51,7 @@ export default function Notes({ clientId }: { clientId: string }) { async function handleAddNote(note: string) { const newNote = { - author: "Agent Name", // TODO get agent name from auth + author: session?.user?.name ?? "Agent", callDate: new Date().toISOString(), dateCreated: new Date().toISOString(), dateUpdated: new Date().toISOString(), diff --git a/src/components/sidebar/index.tsx b/src/components/sidebar/index.tsx index 598b163..c09f433 100644 --- a/src/components/sidebar/index.tsx +++ b/src/components/sidebar/index.tsx @@ -11,8 +11,20 @@ import { ListChecks, Settings, SquareUser, + ChevronsUpDown } from "lucide-react"; + + +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/components/ui/collapsible" +import { useState } from "react"; + + + interface ButtonLinkProps extends React.HTMLAttributes { href: string; } @@ -22,13 +34,14 @@ const ButtonLink = ({ href, children }: ButtonLinkProps) => { const isActive = pathname === href; return ( - + + ); }; @@ -37,6 +50,9 @@ interface SidebarProps extends React.HTMLAttributes { } export default function Sidebar({ className, isProgramManager }: SidebarProps) { + + // const [settingOpen, setSettingOpen] = useState(true); + return (
Clients - - - Settings - + + + + + + Settings + + + + <> + + + + + + + Audit-log + + +
); } diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx new file mode 100644 index 0000000..df61a13 --- /dev/null +++ b/src/components/ui/checkbox.tsx @@ -0,0 +1,30 @@ +"use client" + +import * as React from "react" +import * as CheckboxPrimitive from "@radix-ui/react-checkbox" +import { Check } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Checkbox = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + +)) +Checkbox.displayName = CheckboxPrimitive.Root.displayName + +export { Checkbox } diff --git a/src/components/ui/collapsible.tsx b/src/components/ui/collapsible.tsx new file mode 100644 index 0000000..9fa4894 --- /dev/null +++ b/src/components/ui/collapsible.tsx @@ -0,0 +1,11 @@ +"use client" + +import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" + +const Collapsible = CollapsiblePrimitive.Root + +const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger + +const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent + +export { Collapsible, CollapsibleTrigger, CollapsibleContent } diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx new file mode 100644 index 0000000..5341821 --- /dev/null +++ b/src/components/ui/label.tsx @@ -0,0 +1,26 @@ +"use client" + +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const labelVariants = cva( + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" +) + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/src/components/ui/separator.tsx b/src/components/ui/separator.tsx new file mode 100644 index 0000000..12d81c4 --- /dev/null +++ b/src/components/ui/separator.tsx @@ -0,0 +1,31 @@ +"use client" + +import * as React from "react" +import * as SeparatorPrimitive from "@radix-ui/react-separator" + +import { cn } from "@/lib/utils" + +const Separator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ( + { className, orientation = "horizontal", decorative = true, ...props }, + ref + ) => ( + + ) +) +Separator.displayName = SeparatorPrimitive.Root.displayName + +export { Separator } diff --git a/src/components/ui/single-form.tsx b/src/components/ui/single-form.tsx new file mode 100644 index 0000000..50c7f53 --- /dev/null +++ b/src/components/ui/single-form.tsx @@ -0,0 +1,28 @@ +'use client'; + + +import React from 'react'; +import * as Form from '@radix-ui/react-form'; + +interface SingleFormProps { + onSubmit: (event: React.FormEvent) => void; + fields: { name: string; label: string }[]; +} + +const SingleForm = ({ onSubmit, fields }: SingleFormProps) => { + return ( + + {fields.map((field) => ( + + {field.label} + + + ))} + Submit + + ); +}; + +export default SingleForm; + +export type { SingleFormProps }; diff --git a/src/components/ui/switch.tsx b/src/components/ui/switch.tsx new file mode 100644 index 0000000..bc69cf2 --- /dev/null +++ b/src/components/ui/switch.tsx @@ -0,0 +1,29 @@ +"use client" + +import * as React from "react" +import * as SwitchPrimitives from "@radix-ui/react-switch" + +import { cn } from "@/lib/utils" + +const Switch = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +Switch.displayName = SwitchPrimitives.Root.displayName + +export { Switch } diff --git a/src/components/ui/table.tsx b/src/components/ui/table.tsx new file mode 100644 index 0000000..7f3502f --- /dev/null +++ b/src/components/ui/table.tsx @@ -0,0 +1,117 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Table = React.forwardRef< + HTMLTableElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+ + +)) +Table.displayName = "Table" + +const TableHeader = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableHeader.displayName = "TableHeader" + +const TableBody = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableBody.displayName = "TableBody" + +const TableFooter = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + tr]:last:border-b-0", + className + )} + {...props} + /> +)) +TableFooter.displayName = "TableFooter" + +const TableRow = React.forwardRef< + HTMLTableRowElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableRow.displayName = "TableRow" + +const TableHead = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +TableHead.displayName = "TableHead" + +const TableCell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableCell.displayName = "TableCell" + +const TableCaption = React.forwardRef< + HTMLTableCaptionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +TableCaption.displayName = "TableCaption" + +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +} diff --git a/src/lib/aws/s3.ts b/src/lib/aws/s3.ts new file mode 100644 index 0000000..64e20ac --- /dev/null +++ b/src/lib/aws/s3.ts @@ -0,0 +1,42 @@ +import { + S3Client, + PutObjectCommand, + GetObjectCommand, +} from '@aws-sdk/client-s3'; +import { Readable } from 'stream'; + +const s3 = new S3Client({ region: 'us-east-2' }); +const bucket_name = process.env.BUCKET_NAME; + +export const putObject = async (key: string, body: string) => { + const params = { + Bucket: bucket_name, + Key: key, + Body: body, + }; + const command = new PutObjectCommand(params); + await s3.send(command); +}; + +export const getObjectString = async (key: string) => { + const params = { + Bucket: bucket_name, + Key: key, + }; + const command = new GetObjectCommand(params); + const { Body } = await s3.send(command); + + // handle what happens if object not present + if (!Body) { + throw new Error(`Object not found in s3://${bucket_name}/${key}`); + } + + const stream = Body as Readable; + // convert the stream into a string + const chunks = []; + for await (const chunk of stream) { + chunks.push(chunk); + } + return Buffer.concat(chunks).toString('utf8'); +}; + diff --git a/src/lib/crm/airtable.ts b/src/lib/crm/airtable.ts index 0cd7738..4262c65 100644 --- a/src/lib/crm/airtable.ts +++ b/src/lib/crm/airtable.ts @@ -46,6 +46,25 @@ export class AirtableCRMTable implements CRMTable { }; } + async getAllRows(): Promise { + const airtableUrl = `${AIRTABLE_API_BASE}/${this.baseId}/${this.tableId}`; + + const response = await this.makeAirtableCall(airtableUrl, {}, "GET"); + + // check for error code + if (response.status !== 200) { + throw new Error(`Error fetching data from airtable: ${response.status} - ${response.statusText}`); + } + + const data = await response.json(); + return data.records.map((record: any) => { + return { + id: record.id, + ...record.fields + }; + }); + } + async getRowById(recordId: string): Promise { const airtableUrl = `${AIRTABLE_API_BASE}/${this.baseId}/${this.tableId}/${recordId}`; @@ -73,6 +92,9 @@ export class AirtableCRMTable implements CRMTable { const airtableUrl: string = `${AIRTABLE_API_BASE}/${this.baseId}/${this.tableId}?filterByFormula=${encodedFormula}`; const response = await this.makeAirtableCall(airtableUrl, {}, "GET"); + if (response.status !== 200) { + throw new Error(`Error fetching data from airtable: ${response.status} - ${response.statusText}`); + } return this.parseSingleCrmEntry(response, true); } @@ -127,4 +149,16 @@ export class AirtableCRMProvider implements ConnieCRMProvider { getTable(table_id: string): CRMTable { return new AirtableCRMTable(this.baseId, table_id, this.token); } +} + +export function s3KeyForAirtableToken(oktaId: string): string { + return `crm_airtable_token:${oktaId}`; +} + +export function s3KeyForAirtableBase(oktaId: string): string { + return `crm_airtable_base:${oktaId}`; +} + +export function s3KeyForAirtableTable(oktaId: string): string { + return `crm_airtable_table:${oktaId}`; } \ No newline at end of file diff --git a/src/lib/crm/types.ts b/src/lib/crm/types.ts index d5e04e0..be35e16 100644 --- a/src/lib/crm/types.ts +++ b/src/lib/crm/types.ts @@ -5,6 +5,7 @@ export interface CRMTable { getRowById(id: string): Promise; getClientByPhone(phoneNumber: string): Promise; storeClientByPhone(phoneNumber: string, client: CRMEntry): Promise; + getAllRows(): Promise; } export interface ConnieCRMProvider { diff --git a/src/lib/data/clients.ts b/src/lib/data/clients.ts new file mode 100644 index 0000000..1e09fdc --- /dev/null +++ b/src/lib/data/clients.ts @@ -0,0 +1,42 @@ +import { + AirtableCRMProvider, + s3KeyForAirtableToken, + s3KeyForAirtableBase, + s3KeyForAirtableTable, +} from "../crm/airtable"; +import { getObjectString } from "@/lib/aws/s3"; +import { authOptions } from "@/lib/auth"; +import { getServerSession } from "next-auth/next"; + +// Fetch clients data from crm +export default async function fetchClients() { + const session = (await getServerSession(authOptions)) as any; + + if (!session) { + console.error("Unauthorized"); + return []; + } + + try { + const oktaId = session.oktaId; + + const [airtable_token, airtable_base_id, airtable_table_id] = + await Promise.all([ + getObjectString(s3KeyForAirtableToken(oktaId)), + getObjectString(s3KeyForAirtableBase(oktaId)), + getObjectString(s3KeyForAirtableTable(oktaId)), + ]); + + const provider = new AirtableCRMProvider(airtable_base_id, airtable_token); + const table = provider.getTable(airtable_table_id); + const allClients = await table.getAllRows(); + + allClients.forEach((client) => { + client["full_name"] = `${client.first_name} ${client.last_name}`; + }); + return allClients; + } catch (e) { + console.error(e); + return []; + } +} diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 9d5ac7d..512bbb9 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,5 +1,6 @@ import { type ClassValue, clsx } from "clsx"; import { twMerge } from "tailwind-merge"; +import dayjs from "dayjs"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); @@ -32,3 +33,11 @@ export function formatTime(seconds: number): string { return formattedTime; } + +export function formatDate(date: Date | string | number, format: string = 'YYYY-MM-DD HH:mm') { + return dayjs(date).format(format); +} + +export function copyText(text: string): void { + navigator.clipboard.writeText(text); +} diff --git a/tailwind.config.ts b/tailwind.config.ts index ebaef97..d4cbdf1 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,5 +1,7 @@ import type { Config } from "tailwindcss"; +const withMT = require("@material-tailwind/react/utils/withMT"); + const config = { darkMode: ["class"], content: [ @@ -92,4 +94,4 @@ const config = { plugins: [require("tailwindcss-animate")], } satisfies Config; -export default config; +export default withMT(config);