From 3d2c40b25be0df45df9666fd44679e705cc50f06 Mon Sep 17 00:00:00 2001 From: Joshua Goon Date: Mon, 3 Nov 2025 15:29:37 -0800 Subject: [PATCH 1/3] add pkg --- frontend/package.json | 1 + frontend/yarn.lock | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/frontend/package.json b/frontend/package.json index 2b15dbc..5e27719 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,6 +14,7 @@ "@chakra-ui/react": "^2.4.6", "@emotion/react": "^11.10.5", "@emotion/styled": "^11.10.5", + "@fingerprintjs/fingerprintjs": "^5.0.1", "@next/font": "13.1.1", "eslint": "8.30.0", "eslint-config-next": "^12.0.4", diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 8d6b1d5..f0dc565 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1538,6 +1538,11 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@fingerprintjs/fingerprintjs@^5.0.1": + version "5.0.1" + resolved "https://artifactory.rbx.com/artifactory/api/npm/npm-all/@fingerprintjs/fingerprintjs/-/fingerprintjs-5.0.1.tgz#e6ca2f88719b90e54a0fa8ab2896eee970948bb7" + integrity sha512-KbaeE/rk2WL8MfpRP6jTI4lSr42SJPjvkyrjP3QU6uUDkOMWWYC2Ts1sNSYcegHC8avzOoYTHBj+2fTqvZWQBA== + "@humanwhocodes/config-array@^0.11.8": version "0.11.14" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" From e6a23e7c225557d716cd3f0a521b5a1ba03089bf Mon Sep 17 00:00:00 2001 From: Joshua Goon Date: Mon, 3 Nov 2025 15:29:49 -0800 Subject: [PATCH 2/3] replace localstorage with fingerprint --- frontend/pages/index.jsx | 51 ++++++++++++++++-------------------- frontend/pages/post/[id].jsx | 36 +++++++++---------------- 2 files changed, 35 insertions(+), 52 deletions(-) diff --git a/frontend/pages/index.jsx b/frontend/pages/index.jsx index 5a35f5c..3a36003 100644 --- a/frontend/pages/index.jsx +++ b/frontend/pages/index.jsx @@ -1,3 +1,4 @@ +import FingerprintJS from "@fingerprintjs/fingerprintjs"; import { useState, useRef, useEffect } from "react"; // UI imports // prettier-ignore @@ -23,6 +24,14 @@ import { useErrorToast } from "../hooks/useErrorToast"; import { env_url } from "/utils/api_url"; +const fpPromise = FingerprintJS.load(); + +export const getFingerprintId = async () => { + const fp = await fpPromise; + const result = await fp.get(); + return result.visitorId; +}; + // Google Analytics ID const TRACKING_ID = "UA-253199381-1"; // OUR_TRACKING_ID @@ -66,9 +75,10 @@ export default function Home() { async function fetchPosts(type) { try { + const fingerprintId = await getFingerprintId(); const response = await fetch(`${API_URL}/posts?sort=${type}`, { headers: { - Authorization: `Basic ${btoa(localStorage.getItem("uuid"))}`, + Authorization: `Basic ${btoa(fingerprintId)}`, }, }); const results = await response.json(); @@ -91,25 +101,11 @@ export default function Home() { ReactGA.initialize(TRACKING_ID); ReactGA.pageview(window.location.pathname); - // Check if user has visited already - if (localStorage.getItem("uuid") == null) { - // If not, add UUID to local storage. - localStorage.setItem("uuid", uuidv4()); - setUUID(localStorage.getItem("uuid")); - } else { - setUUID(localStorage.getItem("uuid")); - } - - // if (localStorage.getItem("sort") == null) localStorage.setItem("sort", "0"); - // setSortMethod(parseInt(localStorage.getItem("sort"))); - // if (localStorage.getItem("sort") !== "0") { - // fetchPosts(SORT_ICONS[parseInt(localStorage.getItem("sort")) % SORT_ICONS.length].name.toLowerCase()) - // .then((res) => setPosts(res)) - // .catch((error) => { - // console.error(error); - // addToast(error?.response?.data || error.message); - // }); - // } + // Set UUID to fingerprint ID + (async () => { + const fingerprintId = await getFingerprintId(); + setUUID(fingerprintId); + })(); (async () => { const res = await fetchPosts(SORT_ICONS[sortMethod].name.toLowerCase()); @@ -119,20 +115,17 @@ export default function Home() { setHasMorePosts(!(posts.length === 0)); }, []); - // useEffect(() => { - // localStorage.setItem("sort", sortMethod); - // }, [sortMethod]); - async function loadMore() { try { console.log("Loading"); + const fingerprintId = await getFingerprintId(); const res = await fetch( `${API_URL}/posts?offset=${posts.length}&sort=${SORT_ICONS[sortMethod].name.toLowerCase()}`, { headers: { - Authorization: `Basic ${btoa(localStorage.getItem("uuid"))}`, + Authorization: `Basic ${btoa(fingerprintId)}`, }, - }, + } ); const loadedPosts = await res.json(); if (loadedPosts.length == 0) { @@ -177,7 +170,7 @@ export default function Home() { fetchPosts( SORT_ICONS[ (sortMethod + 1) % SORT_ICONS.length - ].name.toLowerCase(), + ].name.toLowerCase() ) .then((res) => setPosts(res)) .catch((error) => { @@ -228,7 +221,7 @@ export default function Home() { {posts.map( ( post, - i, //TODO theres an error here...duplicate keys + i //TODO theres an error here...duplicate keys ) => (
{/* this is the left and right indicators */} @@ -266,7 +259,7 @@ export default function Home() { key={`${post._id}${i}`} />
- ), + ) )} diff --git a/frontend/pages/post/[id].jsx b/frontend/pages/post/[id].jsx index 5d1acce..cf1c4c7 100644 --- a/frontend/pages/post/[id].jsx +++ b/frontend/pages/post/[id].jsx @@ -26,6 +26,8 @@ import ReactGA from "react-ga"; import { useErrorToast } from "../../hooks/useErrorToast"; +import { getFingerprintId } from "../index"; + // Google Analytics ID const TRACKING_ID = "UA-253199381-1"; // OUR_TRACKING_ID @@ -76,9 +78,10 @@ export default function Home({ queriedPost, id }) { async function fetchPosts(type) { try { + const fingerprintId = await getFingerprintId(); const response = await fetch(`${API_URL}/posts?sort=${type}`, { headers: { - Authorization: `Basic ${btoa(localStorage.getItem("uuid"))}`, + Authorization: `Basic ${btoa(fingerprintId)}`, }, }); const results = await response.json(); @@ -101,25 +104,11 @@ export default function Home({ queriedPost, id }) { ReactGA.initialize(TRACKING_ID); ReactGA.pageview(window.location.pathname); - // Check if user has visited already - if (localStorage.getItem("uuid") == null) { - // If not, add UUID to local storage. - localStorage.setItem("uuid", uuidv4()); - setUUID(localStorage.getItem("uuid")); - } else { - setUUID(localStorage.getItem("uuid")); - } - - // if (localStorage.getItem("sort") == null) localStorage.setItem("sort", "0"); - // setSortMethod(parseInt(localStorage.getItem("sort"))); - // if (localStorage.getItem("sort") !== "0") { - // fetchPosts(SORT_ICONS[parseInt(localStorage.getItem("sort")) % SORT_ICONS.length].name.toLowerCase()) - // .then((res) => setPosts(res)) - // .catch((error) => { - // console.error(error); - // addToast(error?.response?.data || error.message); - // }); - // } + // Set UUID to fingerprint ID + (async () => { + const fingerprintId = await getFingerprintId(); + setUUID(fingerprintId); + })(); (async () => { const res = await fetchPosts("hot"); @@ -136,13 +125,14 @@ export default function Home({ queriedPost, id }) { async function loadMore() { try { + const fingerprintId = await getFingerprintId(); const res = await fetch( `${API_URL}/posts?offset=${posts.length}&sort=${SORT_ICONS[sortMethod].name.toLowerCase()}`, { headers: { - Authorization: `Basic ${btoa(localStorage.getItem("uuid"))}`, + Authorization: `Basic ${btoa(fingerprintId)}`, }, - }, + } ); const loadedPosts = await res.json(); if (loadedPosts.length == 0) { @@ -191,7 +181,7 @@ export default function Home({ queriedPost, id }) { fetchPosts( SORT_ICONS[ (sortMethod + 1) % SORT_ICONS.length - ].name.toLowerCase(), + ].name.toLowerCase() ) .then((res) => setPosts(res)) .catch((error) => { From 16e4e2a93e62dcac81702f8ca97b80d312df7911 Mon Sep 17 00:00:00 2001 From: Joshua Goon Date: Mon, 3 Nov 2025 15:52:11 -0800 Subject: [PATCH 3/3] fix window undefined error --- frontend/pages/index.jsx | 27 +++++++++++++-------------- frontend/pages/post/[id].jsx | 20 +++++++++++++------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/frontend/pages/index.jsx b/frontend/pages/index.jsx index 3a36003..d2272b8 100644 --- a/frontend/pages/index.jsx +++ b/frontend/pages/index.jsx @@ -1,4 +1,3 @@ -import FingerprintJS from "@fingerprintjs/fingerprintjs"; import { useState, useRef, useEffect } from "react"; // UI imports // prettier-ignore @@ -17,21 +16,13 @@ import InfiniteScroll from "react-infinite-scroll-component"; // prettier-ignore import { animateGreen, animateRed, scrollContainer, screenButtonContainer, createButton, sortText, relative } from "../styles/Card.module.css"; // Dependencies -import { v4 as uuidv4 } from "uuid"; +import FingerprintJS from "@fingerprintjs/fingerprintjs"; import ReactGA from "react-ga"; import { useErrorToast } from "../hooks/useErrorToast"; import { env_url } from "/utils/api_url"; -const fpPromise = FingerprintJS.load(); - -export const getFingerprintId = async () => { - const fp = await fpPromise; - const result = await fp.get(); - return result.visitorId; -}; - // Google Analytics ID const TRACKING_ID = "UA-253199381-1"; // OUR_TRACKING_ID @@ -75,10 +66,9 @@ export default function Home() { async function fetchPosts(type) { try { - const fingerprintId = await getFingerprintId(); const response = await fetch(`${API_URL}/posts?sort=${type}`, { headers: { - Authorization: `Basic ${btoa(fingerprintId)}`, + Authorization: `Basic ${btoa(uuid)}`, }, }); const results = await response.json(); @@ -103,6 +93,16 @@ export default function Home() { // Set UUID to fingerprint ID (async () => { + const getFingerprintId = async () => { + if (typeof window === "undefined") { + return null; + } + const fpPromise = FingerprintJS.load(); + const fp = await fpPromise; + const result = await fp.get(); + return result.visitorId; + }; + const fingerprintId = await getFingerprintId(); setUUID(fingerprintId); })(); @@ -118,12 +118,11 @@ export default function Home() { async function loadMore() { try { console.log("Loading"); - const fingerprintId = await getFingerprintId(); const res = await fetch( `${API_URL}/posts?offset=${posts.length}&sort=${SORT_ICONS[sortMethod].name.toLowerCase()}`, { headers: { - Authorization: `Basic ${btoa(fingerprintId)}`, + Authorization: `Basic ${btoa(uuid)}`, }, } ); diff --git a/frontend/pages/post/[id].jsx b/frontend/pages/post/[id].jsx index cf1c4c7..5b1c7f1 100644 --- a/frontend/pages/post/[id].jsx +++ b/frontend/pages/post/[id].jsx @@ -21,13 +21,11 @@ import InfiniteScroll from "react-infinite-scroll-component"; // prettier-ignore import { animateGreen, animateRed, scrollContainer, screenButtonContainer, createButton, sortText, relative } from "../../styles/Card.module.css"; // Dependencies -import { v4 as uuidv4 } from "uuid"; +import FingerprintJS from "@fingerprintjs/fingerprintjs"; import ReactGA from "react-ga"; import { useErrorToast } from "../../hooks/useErrorToast"; -import { getFingerprintId } from "../index"; - // Google Analytics ID const TRACKING_ID = "UA-253199381-1"; // OUR_TRACKING_ID @@ -78,10 +76,9 @@ export default function Home({ queriedPost, id }) { async function fetchPosts(type) { try { - const fingerprintId = await getFingerprintId(); const response = await fetch(`${API_URL}/posts?sort=${type}`, { headers: { - Authorization: `Basic ${btoa(fingerprintId)}`, + Authorization: `Basic ${btoa(uuid)}`, }, }); const results = await response.json(); @@ -106,6 +103,16 @@ export default function Home({ queriedPost, id }) { // Set UUID to fingerprint ID (async () => { + const getFingerprintId = async () => { + if (typeof window === "undefined") { + return null; + } + const fpPromise = FingerprintJS.load(); + const fp = await fpPromise; + const result = await fp.get(); + return result.visitorId; + }; + const fingerprintId = await getFingerprintId(); setUUID(fingerprintId); })(); @@ -125,12 +132,11 @@ export default function Home({ queriedPost, id }) { async function loadMore() { try { - const fingerprintId = await getFingerprintId(); const res = await fetch( `${API_URL}/posts?offset=${posts.length}&sort=${SORT_ICONS[sortMethod].name.toLowerCase()}`, { headers: { - Authorization: `Basic ${btoa(fingerprintId)}`, + Authorization: `Basic ${btoa(uuid)}`, }, } );