From 98352fa68d99a9a160aa108c9a379dd668b0f6d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hl=C3=B6=C3=B0ver=20Sigur=C3=B0sson?= Date: Sun, 15 Dec 2024 15:09:29 +0200 Subject: [PATCH] feat: popular projects (wip) --- functions/.gitignore | 1 + functions/package.json | 3 +- .../src/add_project_file_on_storage_upload.ts | 6 +- functions/src/delete_user.ts | 7 +- functions/src/followers_counter.ts | 6 - functions/src/following_counter.ts | 7 +- functions/src/host.ts | 4 - functions/src/logger.ts | 29 --- functions/src/main.ts | 1 + functions/src/new_user.ts | 7 +- functions/src/popular_projects.ts | 22 +++ functions/src/project_file_storage_delete.ts | 7 +- functions/src/projects_counter.ts | 7 +- functions/yarn.lock | 177 ++++++++++++++++++ src/components/home/actions.ts | 89 ++++----- src/components/home/home.tsx | 57 ++---- src/components/home/popular-projects.tsx | 9 +- src/components/home/project-card.tsx | 4 +- src/components/home/reducer.ts | 9 +- src/components/home/selectors.ts | 12 +- src/components/home/types.ts | 15 +- 21 files changed, 291 insertions(+), 188 deletions(-) delete mode 100644 functions/src/logger.ts create mode 100644 functions/src/popular_projects.ts diff --git a/functions/.gitignore b/functions/.gitignore index 71591451..fd1baa44 100644 --- a/functions/.gitignore +++ b/functions/.gitignore @@ -1,3 +1,4 @@ node_modules/ index.html dist +_local \ No newline at end of file diff --git a/functions/package.json b/functions/package.json index e7eeacbd..a6e8182b 100644 --- a/functions/package.json +++ b/functions/package.json @@ -29,7 +29,8 @@ "@types/lodash-es": "^4.17.12", "eslint": "^9.16.0", "eslint-plugin-promise": "^7.2.1", - "firebase-functions-test": "^3.3.0" + "firebase-functions-test": "^3.3.0", + "tsx": "^4.19.2" }, "private": true } diff --git a/functions/src/add_project_file_on_storage_upload.ts b/functions/src/add_project_file_on_storage_upload.ts index a549c546..9ce9be14 100644 --- a/functions/src/add_project_file_on_storage_upload.ts +++ b/functions/src/add_project_file_on_storage_upload.ts @@ -1,11 +1,7 @@ import admin from "firebase-admin"; -import { initializeApp } from "firebase-admin/app"; import { onObjectFinalized } from "firebase-functions/v2/storage"; -import { makeLogger } from "./logger.js"; +import { log } from "firebase-functions/logger"; -const functionName = "addProjectFileOnStorageUpload"; -initializeApp(undefined, functionName); -const log = makeLogger(functionName); const newTimestamp = admin.firestore.FieldValue.serverTimestamp(); export const addProjectFileOnStorageUploadCallback = onObjectFinalized( diff --git a/functions/src/delete_user.ts b/functions/src/delete_user.ts index 4884a021..743fe281 100644 --- a/functions/src/delete_user.ts +++ b/functions/src/delete_user.ts @@ -1,11 +1,6 @@ import admin from "firebase-admin"; -import { initializeApp } from "firebase-admin/app"; import functions from "firebase-functions/v1"; -import { makeLogger } from "./logger.js"; - -const functionName = "deleteUser"; -initializeApp(undefined, functionName); -const log = makeLogger(functionName); +import { log } from "firebase-functions/logger"; const deleteUserDocument = async ( user: admin.auth.UserRecord diff --git a/functions/src/followers_counter.ts b/functions/src/followers_counter.ts index 6eeb7c24..59e38b02 100644 --- a/functions/src/followers_counter.ts +++ b/functions/src/followers_counter.ts @@ -1,11 +1,5 @@ import admin from "firebase-admin"; -import { initializeApp } from "firebase-admin/app"; import { onDocumentWritten } from "firebase-functions/v2/firestore"; -import { makeLogger } from "./logger.js"; - -const functionName = "followersCounter"; -initializeApp(undefined, functionName); -const log = makeLogger("followersCounter"); export const followersCounter = onDocumentWritten( "followers/{userUid}", diff --git a/functions/src/following_counter.ts b/functions/src/following_counter.ts index 1d6ee065..0e9df0fa 100644 --- a/functions/src/following_counter.ts +++ b/functions/src/following_counter.ts @@ -1,11 +1,6 @@ import admin from "firebase-admin"; -import { initializeApp } from "firebase-admin/app"; import { onDocumentWritten } from "firebase-functions/v2/firestore"; -import { makeLogger } from "./logger.js"; - -const functionName = "followingCounter"; -initializeApp(undefined, functionName); -const log = makeLogger(functionName); +import { log } from "firebase-functions/logger"; export const followingCounter = onDocumentWritten( "following/{userUid}", diff --git a/functions/src/host.ts b/functions/src/host.ts index 4e141f3a..8d97a06e 100644 --- a/functions/src/host.ts +++ b/functions/src/host.ts @@ -1,14 +1,10 @@ import admin from "firebase-admin"; -import { initializeApp } from "firebase-admin/app"; import { onRequest } from "firebase-functions/v2/https"; import { isbot } from "isbot"; import fs from "node:fs"; import path from "node:path"; import * as R from "ramda"; -const functionName = "host"; -initializeApp(undefined, functionName); - function printTree(dirPath: string, indent = "") { const files = fs.readdirSync(dirPath); diff --git a/functions/src/logger.ts b/functions/src/logger.ts deleted file mode 100644 index eb1fa69d..00000000 --- a/functions/src/logger.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Logging } from "@google-cloud/logging"; - -export const makeLogger = (logEntryName: string) => { - const logging = new Logging(); - const logCloudFunction = logging.log(logEntryName); - - const log = (message: string): void => { - const METADATA = { - resource: { - type: "cloud_function", - labels: { - function_name: logEntryName, - region: "us-central1" - } - } - }; - - const data = { - event: `${logEntryName}-event`, - value: message, - message: `${logEntryName}-event: ${message}` - }; - - const entry = logCloudFunction.entry(METADATA, data); - logCloudFunction.write(entry); - }; - - return log; -}; diff --git a/functions/src/main.ts b/functions/src/main.ts index 2cf5b0a4..04d1ff8a 100644 --- a/functions/src/main.ts +++ b/functions/src/main.ts @@ -10,3 +10,4 @@ export { newUserCallback as new_user_callback } from "./new_user.js"; export { projectFileStorageDeleteCallback as project_file_storage_delete_callback } from "./project_file_storage_delete.js"; export { projectsCounter as projects_counter } from "./projects_counter.js"; export { randomProjects as random_projects } from "./random_projects.js"; +export { popularProjects as popular_projects } from "./popular_projects.js"; diff --git a/functions/src/new_user.ts b/functions/src/new_user.ts index c0368303..a86eb57f 100644 --- a/functions/src/new_user.ts +++ b/functions/src/new_user.ts @@ -1,13 +1,8 @@ import { WriteResult } from "@google-cloud/firestore"; import { Timestamp } from "firebase-admin/firestore"; import admin from "firebase-admin"; -import { initializeApp } from "firebase-admin/app"; import functions from "firebase-functions/v1"; -import { makeLogger } from "./logger.js"; - -const functionName = "newUser"; -initializeApp(undefined, functionName); -const log = makeLogger(functionName); +import { log } from "firebase-functions/logger"; async function createProfileDocument( user: admin.auth.UserRecord diff --git a/functions/src/popular_projects.ts b/functions/src/popular_projects.ts new file mode 100644 index 00000000..a44359ce --- /dev/null +++ b/functions/src/popular_projects.ts @@ -0,0 +1,22 @@ +import admin from "firebase-admin"; +import { onCall } from "firebase-functions/v2/https"; +import { log } from "firebase-functions/logger"; +import { shuffle } from "lodash-es"; + +let lastUpdate = Date.now(); +let projects: any[] = []; + +export const popularProjects = onCall<{ count: number }>(async ({ data }) => { + if (projects.length === 0 || Date.now() - lastUpdate > 1000 * 60 * 5) { + lastUpdate = Date.now(); + const db = admin.firestore(); + const randomStars = await db.collection("stars").limit(200).get(); + // log("randomStarsLength: " + randomStars.docs.length); + const projectUids = randomStars.docs.map((doc) => doc.id); + // log("projectUids: " + JSON.stringify(projectUids, null, 2)); + // log("projectsLength: " + projects.length); + projects = projectUids; + } + + return shuffle(projects).slice(0, data.count); +}); diff --git a/functions/src/project_file_storage_delete.ts b/functions/src/project_file_storage_delete.ts index 9713cc15..da0a6399 100644 --- a/functions/src/project_file_storage_delete.ts +++ b/functions/src/project_file_storage_delete.ts @@ -1,12 +1,7 @@ import admin from "firebase-admin"; -import { initializeApp } from "firebase-admin/app"; import { onDocumentDeleted } from "firebase-functions/v2/firestore"; import { config } from "firebase-functions/v1"; -import { makeLogger } from "./logger.js"; - -const functionName = "projectFileStorageDelete"; -initializeApp(undefined, functionName); -const log = makeLogger(functionName); +import { log } from "firebase-functions/logger"; async function projectFileStorageDelete(binaryUrl: string): Promise { log( diff --git a/functions/src/projects_counter.ts b/functions/src/projects_counter.ts index 9fd9b0f2..60981870 100644 --- a/functions/src/projects_counter.ts +++ b/functions/src/projects_counter.ts @@ -1,12 +1,7 @@ import admin from "firebase-admin"; -import { initializeApp } from "firebase-admin/app"; import { FieldValue } from "firebase-admin/firestore"; import { onDocumentWritten } from "firebase-functions/v2/firestore"; -import { makeLogger } from "./logger.js"; - -const functionName = "projectsCounter"; -initializeApp(undefined, functionName); -const log = makeLogger(functionName); +import { log } from "firebase-functions/logger"; export const projectsCounter = onDocumentWritten( "projects/{projectUid}", diff --git a/functions/yarn.lock b/functions/yarn.lock index 62f81ca5..9f524ae3 100644 --- a/functions/yarn.lock +++ b/functions/yarn.lock @@ -36,6 +36,126 @@ resolved "https://registry.yarnpkg.com/@electric-sql/pglite/-/pglite-0.2.15.tgz#c9535b50f311baa317ed7ba0113e2fdc0139e045" integrity sha512-Jiq31Dnk+rg8rMhcSxs4lQvHTyizNo5b269c1gCC3ldQ0sCLrNVPGzy+KnmonKy1ZArTUuXZf23/UamzFMKVaA== +"@esbuild/aix-ppc64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz#51299374de171dbd80bb7d838e1cfce9af36f353" + integrity sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ== + +"@esbuild/android-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz#58565291a1fe548638adb9c584237449e5e14018" + integrity sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw== + +"@esbuild/android-arm@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.23.1.tgz#5eb8c652d4c82a2421e3395b808e6d9c42c862ee" + integrity sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ== + +"@esbuild/android-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.23.1.tgz#ae19d665d2f06f0f48a6ac9a224b3f672e65d517" + integrity sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg== + +"@esbuild/darwin-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz#05b17f91a87e557b468a9c75e9d85ab10c121b16" + integrity sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q== + +"@esbuild/darwin-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz#c58353b982f4e04f0d022284b8ba2733f5ff0931" + integrity sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw== + +"@esbuild/freebsd-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz#f9220dc65f80f03635e1ef96cfad5da1f446f3bc" + integrity sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA== + +"@esbuild/freebsd-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz#69bd8511fa013b59f0226d1609ac43f7ce489730" + integrity sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g== + +"@esbuild/linux-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz#8050af6d51ddb388c75653ef9871f5ccd8f12383" + integrity sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g== + +"@esbuild/linux-arm@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz#ecaabd1c23b701070484990db9a82f382f99e771" + integrity sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ== + +"@esbuild/linux-ia32@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz#3ed2273214178109741c09bd0687098a0243b333" + integrity sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ== + +"@esbuild/linux-loong64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz#a0fdf440b5485c81b0fbb316b08933d217f5d3ac" + integrity sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw== + +"@esbuild/linux-mips64el@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz#e11a2806346db8375b18f5e104c5a9d4e81807f6" + integrity sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q== + +"@esbuild/linux-ppc64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz#06a2744c5eaf562b1a90937855b4d6cf7c75ec96" + integrity sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw== + +"@esbuild/linux-riscv64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz#65b46a2892fc0d1af4ba342af3fe0fa4a8fe08e7" + integrity sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA== + +"@esbuild/linux-s390x@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz#e71ea18c70c3f604e241d16e4e5ab193a9785d6f" + integrity sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw== + +"@esbuild/linux-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz#d47f97391e80690d4dfe811a2e7d6927ad9eed24" + integrity sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ== + +"@esbuild/netbsd-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz#44e743c9778d57a8ace4b72f3c6b839a3b74a653" + integrity sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA== + +"@esbuild/openbsd-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz#05c5a1faf67b9881834758c69f3e51b7dee015d7" + integrity sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q== + +"@esbuild/openbsd-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz#2e58ae511bacf67d19f9f2dcd9e8c5a93f00c273" + integrity sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA== + +"@esbuild/sunos-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz#adb022b959d18d3389ac70769cef5a03d3abd403" + integrity sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA== + +"@esbuild/win32-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz#84906f50c212b72ec360f48461d43202f4c8b9a2" + integrity sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A== + +"@esbuild/win32-ia32@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz#5e3eacc515820ff729e90d0cb463183128e82fac" + integrity sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ== + +"@esbuild/win32-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz#81fd50d11e2c32b2d6241470e3185b70c7b30699" + integrity sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg== + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -2080,6 +2200,36 @@ es-errors@^1.3.0: resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +esbuild@~0.23.0: + version "0.23.1" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.23.1.tgz#40fdc3f9265ec0beae6f59824ade1bd3d3d2dab8" + integrity sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.23.1" + "@esbuild/android-arm" "0.23.1" + "@esbuild/android-arm64" "0.23.1" + "@esbuild/android-x64" "0.23.1" + "@esbuild/darwin-arm64" "0.23.1" + "@esbuild/darwin-x64" "0.23.1" + "@esbuild/freebsd-arm64" "0.23.1" + "@esbuild/freebsd-x64" "0.23.1" + "@esbuild/linux-arm" "0.23.1" + "@esbuild/linux-arm64" "0.23.1" + "@esbuild/linux-ia32" "0.23.1" + "@esbuild/linux-loong64" "0.23.1" + "@esbuild/linux-mips64el" "0.23.1" + "@esbuild/linux-ppc64" "0.23.1" + "@esbuild/linux-riscv64" "0.23.1" + "@esbuild/linux-s390x" "0.23.1" + "@esbuild/linux-x64" "0.23.1" + "@esbuild/netbsd-x64" "0.23.1" + "@esbuild/openbsd-arm64" "0.23.1" + "@esbuild/openbsd-x64" "0.23.1" + "@esbuild/sunos-x64" "0.23.1" + "@esbuild/win32-arm64" "0.23.1" + "@esbuild/win32-ia32" "0.23.1" + "@esbuild/win32-x64" "0.23.1" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -2735,6 +2885,11 @@ fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -2804,6 +2959,13 @@ get-stdin@=8.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== +get-tsconfig@^4.7.5: + version "4.8.1" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.1.tgz#8995eb391ae6e1638d251118c7b56de7eb425471" + integrity sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg== + dependencies: + resolve-pkg-maps "^1.0.0" + get-uri@^6.0.1: version "6.0.3" resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-6.0.3.tgz#0d26697bc13cf91092e519aa63aa60ee5b6f385a" @@ -4721,6 +4883,11 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" @@ -5352,6 +5519,16 @@ tsscmp@^1.0.6: resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA== +tsx@^4.19.2: + version "4.19.2" + resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.19.2.tgz#2d7814783440e0ae42354d0417d9c2989a2ae92c" + integrity sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g== + dependencies: + esbuild "~0.23.0" + get-tsconfig "^4.7.5" + optionalDependencies: + fsevents "~2.3.3" + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" diff --git a/src/components/home/actions.ts b/src/components/home/actions.ts index 7b3f45a9..c6ed99e0 100644 --- a/src/components/home/actions.ts +++ b/src/components/home/actions.ts @@ -1,7 +1,7 @@ import { difference, keys, isEmpty, pluck } from "ramda"; import { getFunctions, httpsCallable } from "firebase/functions"; import { documentId, getDocs, query, where } from "firebase/firestore"; -import { profiles, projects } from "@config/firestore"; +import { profiles } from "@config/firestore"; import { RootState } from "@root/store"; import { ADD_USER_PROFILES, @@ -12,14 +12,11 @@ import { SET_POPULAR_PROJECTS_OFFSET, SET_RANDOM_PROJECTS_LOADING, HomeActionTypes, - RandomProjectResponse + RandomProjectResponse, + PopularProjectResponse } from "./types"; import { IProject } from "@comp/projects/types"; -import { - convertProjectSnapToProject, - firestoreProjectToIProject -} from "@comp/projects/utils"; -import { IStarredProjectSearchResult, IStarredProject } from "@db/search"; +import { firestoreProjectToIProject } from "@comp/projects/utils"; const databaseID = process.env.REACT_APP_DATABASE === "DEV" ? "dev" : "prod"; const searchURL = `https://web-ide-search-api.csound.com/search/${databaseID}`; @@ -28,6 +25,10 @@ const getRandomProjects = httpsCallable< { count: number }, RandomProjectResponse[] >(functions, "random_projects"); +const getPopularProjects = httpsCallable< + { count: number }, + PopularProjectResponse[] +>(functions, "popular_projects"); // const searchURL = `http://localhost:4000/search/${databaseID}`; @@ -64,7 +65,7 @@ export const searchProjects = const projectProfiles = {}; const profilesQuery = await getDocs( - (query as any)(profiles, where(documentId(), "in", userIDs)) + query(profiles, where(documentId(), "in", userIDs)) ); profilesQuery.forEach((snapshot) => { @@ -101,8 +102,7 @@ export const fetchPopularProjects = (offset = 0, pageSize = 8) => { }); const state = getState().HomeReducer; - let starsIDs: string[] = []; - let totalRecords = 0; + let popularProjects: PopularProjectResponse[] = []; try { // const starsRequest = await fetch( // `${searchURL}/list/stars/${pageSize}/${offset}/count/desc` @@ -110,62 +110,43 @@ export const fetchPopularProjects = (offset = 0, pageSize = 8) => { // const starredProjects: IStarredProjectSearchResult = // await starsRequest.json(); - const starredProjects = { data: [] }; - - starsIDs = starredProjects.data.map( - (item: IStarredProject) => item.id - ); + const popularProjectsResponse = await getPopularProjects({ + count: pageSize + }); - totalRecords = 0; //starredProjects.totalRecords as number; + popularProjects = []; // popularProjectsResponse.data; } catch (error) { console.error(error); } - if (!isEmpty(starsIDs)) { - const publicProjectsSnapshots = await getDocs( - query( - query(projects, where("public", "==", true)), - where(documentId(), "in", starsIDs) - ) - ); - const popularProjects: IProject[] = await Promise.all( - publicProjectsSnapshots.docs.map( - async (snap) => await convertProjectSnapToProject(snap) - ) - ); - - const userIDs = pluck("userUid", popularProjects); + const userIDs = popularProjects.map((project) => project.userUid); - const missingProfiles = difference(userIDs, keys(state.profiles)); - if (!isEmpty(missingProfiles)) { - const projectProfiles = {}; - - const profilesQuery = await getDocs( - query(profiles, where(documentId(), "in", missingProfiles)) - ); + const missingProfiles = difference(userIDs, keys(state.profiles)); + if (!isEmpty(missingProfiles)) { + const projectProfiles = {}; - profilesQuery.forEach((snapshot) => { - projectProfiles[snapshot.id] = snapshot.data(); - if (projectProfiles[snapshot.id]?.userJoinDate) { - projectProfiles[snapshot.id].userJoinDate = - projectProfiles[ - snapshot.id - ].userJoinDate.toMillis(); - } - }); + const profilesQuery = await getDocs( + query(profiles, where(documentId(), "in", missingProfiles)) + ); - dispatch({ - type: ADD_USER_PROFILES, - payload: projectProfiles - }); - } + profilesQuery.forEach((snapshot) => { + projectProfiles[snapshot.id] = snapshot.data(); + if (projectProfiles[snapshot.id]?.userJoinDate) { + projectProfiles[snapshot.id].userJoinDate = + projectProfiles[snapshot.id].userJoinDate.toMillis(); + } + }); dispatch({ - type: ADD_POPULAR_PROJECTS, - payload: popularProjects, - totalRecords + type: ADD_USER_PROFILES, + payload: projectProfiles }); } + + dispatch({ + type: ADD_POPULAR_PROJECTS, + payload: popularProjects + }); }; }; diff --git a/src/components/home/home.tsx b/src/components/home/home.tsx index a26f1a6c..d4ff004d 100644 --- a/src/components/home/home.tsx +++ b/src/components/home/home.tsx @@ -14,8 +14,9 @@ import { const Home = (): React.ReactElement => { const dispatch = useDispatch(); - const [popularProjectsFetchOffset, popularProjectsTotalRecords] = - useSelector(selectPopularProjectsFetchOffset); + const popularProjectsFetchOffset = useSelector( + selectPopularProjectsFetchOffset + ); const [currentPopularProjectsOffset, setCurrentPopularProjectsOffset] = useState(0); @@ -30,36 +31,23 @@ const Home = (): React.ReactElement => { ); const handlePopularProjectsNextPage = useCallback(() => { - if ( - popularProjectsTotalRecords > 0 && - currentPopularProjectsOffset < popularProjectsTotalRecords - ) { - let popularProjects; - try { - popularProjects = fetchPopularProjects( - currentPopularProjectsOffset - ); - } catch (error) { - console.error(error); - } - if (popularProjects) { - dispatch(popularProjects); - setCurrentPopularProjectsOffset( - currentPopularProjectsOffset + 8 - ); - } + try { + dispatch(fetchPopularProjects(currentPopularProjectsOffset)); + } catch (error) { + console.error(error); } - }, [dispatch, popularProjectsTotalRecords, currentPopularProjectsOffset]); + // if (popularProjects) { + // dispatch(popularProjects); + // setCurrentPopularProjectsOffset( + // currentPopularProjectsOffset + 8 + // ); + // } + }, [dispatch, currentPopularProjectsOffset]); const handlePopularProjectsPreviousPage = useCallback(() => { - if ( - popularProjectsTotalRecords > 0 && - currentPopularProjectsOffset > 0 - ) { - dispatch(fetchPopularProjects(currentPopularProjectsOffset)); - setCurrentPopularProjectsOffset(currentPopularProjectsOffset - 8); - } - }, [dispatch, popularProjectsTotalRecords, currentPopularProjectsOffset]); + dispatch(fetchPopularProjects(currentPopularProjectsOffset)); + setCurrentPopularProjectsOffset(currentPopularProjectsOffset - 8); + }, [dispatch, currentPopularProjectsOffset]); useEffect(() => { if (popularProjectsFetchOffset < 0) { @@ -80,8 +68,8 @@ const Home = (): React.ReactElement => {
{/* */} -

Search is being fixed...

- Search is being fixed...

*/} + {/* { handlePopularProjectsPreviousPage={ handlePopularProjectsPreviousPage } - hasNext={ - popularProjectsTotalRecords > 0 && - currentPopularProjectsOffset < - popularProjectsTotalRecords - } hasPrevious={currentPopularProjectsOffset > 0} - /> + /> */}
diff --git a/src/components/home/popular-projects.tsx b/src/components/home/popular-projects.tsx index 4b1c2657..ab301ff3 100644 --- a/src/components/home/popular-projects.tsx +++ b/src/components/home/popular-projects.tsx @@ -7,19 +7,18 @@ import RightIcon from "@mui/icons-material/ArrowForward"; import IconButton from "@mui/material/IconButton"; import { Theme, useTheme } from "@emotion/react"; import { ProjectCard, ProjectCardSkeleton } from "./project-card"; +import { PopularProjectResponse } from "./types"; import * as SS from "./styles"; const PopularProjects = ({ projects, handlePopularProjectsNextPage, handlePopularProjectsPreviousPage, - hasNext, hasPrevious }: { - projects: IProject[]; + projects: PopularProjectResponse[]; handlePopularProjectsNextPage: () => void; handlePopularProjectsPreviousPage: () => void; - hasNext: boolean; hasPrevious: boolean; }): React.ReactElement => { const theme: Theme = useTheme(); @@ -52,9 +51,9 @@ const PopularProjects = ({ diff --git a/src/components/home/project-card.tsx b/src/components/home/project-card.tsx index bfe7026e..7dba2a5f 100644 --- a/src/components/home/project-card.tsx +++ b/src/components/home/project-card.tsx @@ -19,7 +19,7 @@ import { Photo, ProjectCardContentBottomID } from "./home-ui"; -import { RandomProjectResponse } from "./types"; +import { RandomProjectResponse, PopularProjectResponse } from "./types"; import * as SS from "./styles"; export const ProjectCardSkeleton = ({ theme }: { theme: Theme }) => ( @@ -38,7 +38,7 @@ export const ProjectCard = ({ }: { projectIndex: number; profile: IProfile; - project: IProject | RandomProjectResponse; + project: IProject | RandomProjectResponse | PopularProjectResponse; }) => { return ( diff --git a/src/components/home/reducer.ts b/src/components/home/reducer.ts index 998ece0f..7f811eb8 100644 --- a/src/components/home/reducer.ts +++ b/src/components/home/reducer.ts @@ -10,12 +10,11 @@ import { } from "./types"; import { IProject } from "@comp/projects/types"; import { IProfile } from "@comp/profile/types"; -import { RandomProjectResponse } from "./types"; +import { RandomProjectResponse, PopularProjectResponse } from "./types"; export interface IHomeReducer { - popularProjects: IProject[]; + popularProjects: PopularProjectResponse[]; popularProjectsOffset: number; - popularProjectsTotalRecords: number; profiles: { [uid: string]: IProfile }; searchProjectsRequest: boolean; searchResult: IProject[]; @@ -29,7 +28,6 @@ export interface IHomeReducer { const INITIAL_STATE: IHomeReducer = { popularProjects: [], popularProjectsOffset: -1, - popularProjectsTotalRecords: -1, profiles: {}, searchProjectsRequest: false, searchResult: [], @@ -76,8 +74,7 @@ const HomeReducer = ( case ADD_POPULAR_PROJECTS: { return { ...state, - popularProjects: [...state.popularProjects, ...action.payload], - popularProjectsTotalRecords: action.totalRecords + popularProjects: [...state.popularProjects, ...action.payload] }; } case SET_POPULAR_PROJECTS_OFFSET: { diff --git a/src/components/home/selectors.ts b/src/components/home/selectors.ts index ec57db5f..e584176a 100644 --- a/src/components/home/selectors.ts +++ b/src/components/home/selectors.ts @@ -1,7 +1,7 @@ import { IHomeReducer } from "./reducer"; import { IProject } from "@comp/projects/types"; import { RootState } from "@root/store"; -import { slice } from "ramda"; +import { PopularProjectResponse } from "./types"; // export const selectDisplayedStarredProjects = ( // store: IStore @@ -106,19 +106,17 @@ import { slice } from "ramda"; // } // ); -export const selectPopularProjectsFetchOffset = ( - store: RootState -): number[] => { +export const selectPopularProjectsFetchOffset = (store: RootState): number => { const state: IHomeReducer = store.HomeReducer; - return [state.popularProjectsOffset, state.popularProjectsTotalRecords]; + return state.popularProjectsOffset; }; export const selectPopularProjectsSlice = (from: number, to: number) => - (store: RootState): IProject[] => { + (store: RootState): PopularProjectResponse[] => { const state: IHomeReducer = store.HomeReducer; const popularProjects = state.popularProjects; - return slice(from, to, popularProjects); + return popularProjects.slice(from, to); }; export const selectSearchResult = (store: RootState): IProject[] => { diff --git a/src/components/home/types.ts b/src/components/home/types.ts index a84bcd33..2797d93a 100644 --- a/src/components/home/types.ts +++ b/src/components/home/types.ts @@ -22,6 +22,18 @@ export interface RandomProjectResponse { userUid: string; } +export interface PopularProjectResponse { + created: Timestamp; + description: string; + iconBackgroundColor: string | undefined; + iconForegroundColor: string | undefined; + iconName: string | undefined; + name: string; + projectUid: string; + public: boolean; + userUid: string; +} + interface SearchProjectsRequest { type: typeof SEARCH_PROJECTS_REQUEST; query: string; @@ -41,8 +53,7 @@ interface AddUserProfiles { interface AddPopularProjectsAction { type: typeof ADD_POPULAR_PROJECTS; - payload: IProject[]; - totalRecords: number; + payload: PopularProjectResponse[]; } interface SetPopularProjectsOffsetAction {