diff --git a/apps/site/app/[username]/page.tsx b/apps/site/app/[username]/page.tsx index 58a3c3a7b..5591d5fa4 100644 --- a/apps/site/app/[username]/page.tsx +++ b/apps/site/app/[username]/page.tsx @@ -1,6 +1,6 @@ -import { Button, Flex, Grid, Stack, Typography } from '@/design-system' +import { Flex, Grid, Stack, Typography } from '@/design-system' import { getChannelsItemsWithUser } from '@/gql' -import { getDataForUsername } from '@/lib' +import { getDataForUsername, getItemsWithUserId } from '@/lib' import { ChannelCard } from '@/server' import { pluralize, sortChannels } from '@/utils' import { ChannelDialog, NewChannelTrigger, UserSettings } from '@/client' @@ -11,6 +11,7 @@ export default async function Profile({ params: { username: string } }) { const userData = await getDataForUsername({ username: params.username }) + let channels let items @@ -23,6 +24,8 @@ export default async function Profile({ items = itemsResp } + const { itemsWithUserId } = await getItemsWithUserId(userData.id) + // @ts-ignore const sortedChannels = channels?.items ? sortChannels(channels.items) : [] @@ -35,7 +38,7 @@ export default async function Profile({ {pluralize(sortedChannels.length as number, 'channel', 'channels')},{' '} - {pluralize(items?.items?.length as number, 'item', 'items')} + {pluralize(itemsWithUserId as number, 'item', 'items')} diff --git a/apps/site/config/pgPool.ts b/apps/site/config/pgPool.ts new file mode 100644 index 000000000..a1fc994be --- /dev/null +++ b/apps/site/config/pgPool.ts @@ -0,0 +1,9 @@ +'server-only' + +import pg from 'pg' + +const { Pool } = pg + +export const pgPool = new Pool({ + connectionString: process.env.DATABASE_URL, +}) diff --git a/apps/site/lib/actions/getItemsWithUserId.ts b/apps/site/lib/actions/getItemsWithUserId.ts new file mode 100644 index 000000000..04b173fd0 --- /dev/null +++ b/apps/site/lib/actions/getItemsWithUserId.ts @@ -0,0 +1,16 @@ +'use server' + +import { pgPool } from '@/config/pgPool' + +export async function getItemsWithUserId(createdById: number) { + try { + await pgPool.connect() + const query = + 'SELECT COUNT(*) FROM "public"."Item" WHERE "createdById" = $1;' + const res = await pgPool.query(query, [createdById]) + return { itemsWithUserId: res.rows[0].count } + } catch (err) { + console.error(err) + return { itemsWithUserId: 0 } // Ensure a return on error + } +} diff --git a/apps/site/lib/actions/index.ts b/apps/site/lib/actions/index.ts index 3284a9efb..a474919aa 100644 --- a/apps/site/lib/actions/index.ts +++ b/apps/site/lib/actions/index.ts @@ -1 +1,2 @@ +export * from './getItemsWithUserId' export * from './revalidationHelper' diff --git a/apps/site/package.json b/apps/site/package.json index 721608580..0852b1d1b 100644 --- a/apps/site/package.json +++ b/apps/site/package.json @@ -45,6 +45,7 @@ "nextjs-toploader": "^1.6.11", "p-queue": "^8.0.1", "p-retry": "^6.2.0", + "pg": "^8.11.5", "react": "18.2.0", "react-dom": "18.2.0", "react-dropzone": "^14.2.3", @@ -71,6 +72,7 @@ "@graphql-codegen/typescript-graphql-request": "^5.0.0", "@graphql-codegen/typescript-operations": "^4.0.1", "@types/node": "^20.5.6", + "@types/pg": "^8.11.6", "@types/react": "18.2.21", "@types/react-dom": "18.2.7", "autoprefixer": "10.4.15", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2762ea711..711734e7c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -178,6 +178,9 @@ importers: p-retry: specifier: ^6.2.0 version: 6.2.0 + pg: + specifier: ^8.11.5 + version: 8.11.5 react: specifier: 18.2.0 version: 18.2.0 @@ -251,6 +254,9 @@ importers: '@types/node': specifier: ^20.5.6 version: 20.5.6 + '@types/pg': + specifier: ^8.11.6 + version: 8.11.6 '@types/react': specifier: 18.2.21 version: 18.2.21 @@ -5085,7 +5091,6 @@ packages: resolution: {integrity: sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==} dependencies: undici-types: 5.26.5 - dev: false /@types/node@20.5.6: resolution: {integrity: sha512-Gi5wRGPbbyOTX+4Y2iULQ27oUPrefaB0PxGQJnfyWN3kvEDGM3mIB5M/gQLmitZf7A9FmLeaqxD3L1CXpm3VKQ==} @@ -5105,6 +5110,14 @@ packages: '@types/node': 20.11.19 dev: false + /@types/pg@8.11.6: + resolution: {integrity: sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==} + dependencies: + '@types/node': 20.11.19 + pg-protocol: 1.6.1 + pg-types: 4.0.2 + dev: true + /@types/prop-types@15.7.10: resolution: {integrity: sha512-mxSnDQxPqsZxmeShFH+uwQ4kO4gcJcGahjjMFeLbKE95IAZiiZyiEepGZjtXJ7hN/yfu0bu9xN2ajcU0JcxX6A==} @@ -11299,6 +11312,10 @@ packages: http-https: 1.0.0 dev: false + /obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + dev: true + /ofetch@1.3.3: resolution: {integrity: sha512-s1ZCMmQWXy4b5K/TW9i/DtiN8Ku+xCiHcjQ6/J/nDdssirrQNOoB165Zu8EqLMA2lln1JUth9a0aW9Ap2ctrUg==} dependencies: @@ -11678,10 +11695,18 @@ packages: resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} dev: false + /pg-connection-string@2.6.4: + resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==} + dev: false + /pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} - dev: false + + /pg-numeric@1.0.2: + resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} + engines: {node: '>=4'} + dev: true /pg-pool@3.6.1(pg@8.11.3): resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==} @@ -11691,10 +11716,21 @@ packages: pg: 8.11.3 dev: false + /pg-pool@3.6.2(pg@8.11.5): + resolution: {integrity: sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==} + peerDependencies: + pg: '>=8.0' + dependencies: + pg: 8.11.5 + dev: false + /pg-protocol@1.6.0: resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==} dev: false + /pg-protocol@1.6.1: + resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==} + /pg-types@2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} @@ -11706,6 +11742,19 @@ packages: postgres-interval: 1.2.0 dev: false + /pg-types@4.0.2: + resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} + engines: {node: '>=10'} + dependencies: + pg-int8: 1.0.1 + pg-numeric: 1.0.2 + postgres-array: 3.0.2 + postgres-bytea: 3.0.0 + postgres-date: 2.1.0 + postgres-interval: 3.0.0 + postgres-range: 1.1.4 + dev: true + /pg@8.11.3: resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==} engines: {node: '>= 8.0.0'} @@ -11726,6 +11775,24 @@ packages: pg-cloudflare: 1.1.1 dev: false + /pg@8.11.5: + resolution: {integrity: sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + dependencies: + pg-connection-string: 2.6.4 + pg-pool: 3.6.2(pg@8.11.5) + pg-protocol: 1.6.1 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.1.1 + dev: false + /pgpass@1.0.5: resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} dependencies: @@ -11945,16 +12012,33 @@ packages: engines: {node: '>=4'} dev: false + /postgres-array@3.0.2: + resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} + engines: {node: '>=12'} + dev: true + /postgres-bytea@1.0.0: resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} engines: {node: '>=0.10.0'} dev: false + /postgres-bytea@3.0.0: + resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} + engines: {node: '>= 6'} + dependencies: + obuf: 1.1.2 + dev: true + /postgres-date@1.0.7: resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} engines: {node: '>=0.10.0'} dev: false + /postgres-date@2.1.0: + resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} + engines: {node: '>=12'} + dev: true + /postgres-interval@1.2.0: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} @@ -11962,6 +12046,15 @@ packages: xtend: 4.0.2 dev: false + /postgres-interval@3.0.0: + resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} + engines: {node: '>=12'} + dev: true + + /postgres-range@1.1.4: + resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} + dev: true + /preact@10.19.2: resolution: {integrity: sha512-UA9DX/OJwv6YwP9Vn7Ti/vF80XL+YA5H2l7BpCtUr3ya8LWHFzpiO5R+N7dN16ujpIxhekRFuOOF82bXX7K/lg==} dev: false