-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lib-user: Refactor usePanoptesProjects hook with auth, update usage accordingly #6140
Changes from all commits
c77e861
e8a378e
6c67fb3
09642fc
9fcf48a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,7 +20,6 @@ async function fetchUserProjectPreferences() { | |
const authorization = `Bearer ${token}` | ||
try { | ||
const query = { | ||
page: 1, // returns 20 items | ||
sort: '-updated_at', | ||
user_id: user.id | ||
} | ||
|
@@ -29,7 +28,6 @@ async function fetchUserProjectPreferences() { | |
const projectPreferencesUserHasClassified = | ||
response.body.project_preferences | ||
.filter(preference => preference.activity_count > 0) | ||
.slice(0, 10) | ||
return projectPreferencesUserHasClassified | ||
} | ||
return [] | ||
|
@@ -39,7 +37,7 @@ async function fetchUserProjectPreferences() { | |
} | ||
} | ||
|
||
export default function RecentProjectsContainer({ authUser }) { | ||
function RecentProjectsContainer({ authUser }) { | ||
// Get user's project preference.activity_count for 10 most recently classified projects | ||
const cacheKey = { | ||
name: 'user-project-preferences', | ||
|
@@ -59,21 +57,27 @@ export default function RecentProjectsContainer({ authUser }) { | |
data: projects, | ||
isLoading: projectsLoading, | ||
error: projectsError | ||
} = usePanoptesProjects(recentProjectIds) | ||
|
||
} = usePanoptesProjects({ | ||
cards: true, | ||
id: recentProjectIds?.join(',') | ||
}) | ||
|
||
// Attach project object to each project preference | ||
let projectPreferencesWithProjectObj | ||
|
||
if (projects?.length) { | ||
projectPreferencesWithProjectObj = projectPreferences?.map(preference => { | ||
const matchedProjectObj = projects.find( | ||
project => project.id === preference.links.project | ||
) | ||
projectPreferencesWithProjectObj = projectPreferences | ||
.map(preference => { | ||
const matchedProjectObj = projects.find( | ||
project => project.id === preference.links?.project | ||
) | ||
|
||
if (matchedProjectObj) { | ||
preference.project = matchedProjectObj | ||
} | ||
return preference | ||
}) | ||
if (matchedProjectObj) { | ||
preference.project = matchedProjectObj | ||
} | ||
return preference | ||
}) | ||
.filter(preference => preference?.project?.slug) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This filter will help prevent similar crashes. |
||
.slice(0, 10) | ||
} | ||
|
||
return ( | ||
|
@@ -90,3 +94,5 @@ RecentProjectsContainer.propTypes = { | |
id: string | ||
}) | ||
} | ||
|
||
export default RecentProjectsContainer |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,6 @@ const SWROptions = { | |
async function fetchUserRecents({ userId }) { | ||
try { | ||
const query = { | ||
page_size: 10, | ||
sort: '-created_at' | ||
} | ||
const response = await panoptes.get(`/users/${userId}/recents`, query) | ||
|
@@ -36,16 +35,31 @@ function RecentSubjectsContainer({ authUser }) { | |
|
||
const recentProjectIds = [...new Set(recents?.map(recent => recent.links?.project))] | ||
|
||
const { data: projects, isLoading: projectsLoading, error: projectsError } = usePanoptesProjects(recentProjectIds) | ||
const { | ||
data: projects, | ||
isLoading: projectsLoading, | ||
error: projectsError | ||
} = usePanoptesProjects({ | ||
cards: true, | ||
id: recentProjectIds?.join(',') | ||
}) | ||
|
||
// Attach project slug to each recent | ||
let recentsWithProjectSlugs | ||
if (projects?.length) { | ||
recentsWithProjectSlugs = recents.map(recent => { | ||
const { slug } = projects.find(project => recent.links.project === project.id) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @shaunanoordin - this was the cause of the page crash. The recents included a project that was not included in the |
||
recent.project_slug = slug | ||
return recent | ||
}) | ||
recentsWithProjectSlugs = recents | ||
.map(recent => { | ||
const matchedProjectObj = projects.find( | ||
project => project.id === recent.links?.project | ||
) | ||
|
||
if (matchedProjectObj) { | ||
recent.projectSlug = matchedProjectObj.slug | ||
} | ||
return recent | ||
Comment on lines
+56
to
+59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'm now curious to see if any other component that uses Similar suggestion applies: create a copy of the project before modifying and returning it.
|
||
}) | ||
.filter(recent => recent?.projectSlug) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This filter will help prevent similar crashes. |
||
.slice(0, 10) | ||
} | ||
|
||
const error = recentsError || projectsError | ||
|
@@ -60,10 +74,10 @@ function RecentSubjectsContainer({ authUser }) { | |
) | ||
} | ||
|
||
export default RecentSubjectsContainer | ||
|
||
RecentSubjectsContainer.propTypes = { | ||
authUser: shape({ | ||
id: string | ||
}) | ||
} | ||
|
||
export default RecentSubjectsContainer |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,9 @@ | ||
import { projects as panoptesProjects } from '@zooniverse/panoptes-js' | ||
import auth from 'panoptes-client/lib/auth' | ||
import useSWR from 'swr' | ||
|
||
const isBrowser = typeof window !== 'undefined' | ||
|
||
const SWROptions = { | ||
revalidateIfStale: true, | ||
revalidateOnMount: true, | ||
|
@@ -9,17 +12,28 @@ const SWROptions = { | |
refreshInterval: 0 | ||
} | ||
|
||
async function fetchProjects(id) { | ||
if (isBrowser) { | ||
auth.checkCurrent() | ||
} | ||
Comment on lines
+15
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [curiosity] This is the first time I'm seeing this pattern - auth.checkCurrent() is placed in the root function? Is this synchronous and will this block execution of the rest of the code, until auth current is checked? Or it is running asynchronously as the rest of the page executes? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code is asynchronous and won't block other code execution. It's similar to what is implemented in lib-react-components' useUnreadMessages and useUnreadNotifications hooks. |
||
|
||
async function fetchProjects(query) { | ||
let token = await auth.checkBearerToken() | ||
if (!token) { | ||
await auth.checkCurrent() | ||
token = await auth.checkBearerToken() | ||
} | ||
const authorization = token ? `Bearer ${token}` : undefined | ||
|
||
let projectsAccumulator = [] | ||
|
||
async function getProjects (page = 1) { | ||
const query = { | ||
cards: true, | ||
id, | ||
page, | ||
page_size: 100 | ||
} | ||
const response = await panoptesProjects.get({ query }) | ||
const response = await panoptesProjects.get({ | ||
query: { | ||
page, | ||
...query | ||
}, | ||
authorization | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [observation] Ah, so what was missing previously was the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Because if there's no user, the If If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Refactored as noted - |
||
}) | ||
const { meta, projects } = response?.body || {} | ||
|
||
if (meta?.projects?.page_count > 5) { | ||
|
@@ -42,11 +56,10 @@ async function fetchProjects(id) { | |
return projectsAccumulator | ||
} | ||
|
||
export function usePanoptesProjects(projectIds) { | ||
export function usePanoptesProjects(query) { | ||
let key = null | ||
if (projectIds) { | ||
const id = projectIds.join(',') | ||
key = id | ||
if (query?.id) { | ||
key = query | ||
} | ||
return useSWR(key, fetchProjects, SWROptions) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think
preference.project = whatever
will actually modify the original object(s) in theprojectPreferences[]
array (aka the data fetched viafetchUserProjectPreferences()
).In practice, this is fine because I don't see anything else using
projectPreferences
, nor for that matter theresponse.body.project_preferences
data being pulled inRecentProjectsContainer.fetchUserProjectPreferences()
.Recommendation: make a copy of the object you want to modify and return. e.g.: