Skip to content
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

Austenem/CAT-754 Refactor "My Lists" #3671

Open
wants to merge 36 commits into
base: main
Choose a base branch
from

Conversation

austenem
Copy link
Collaborator

@austenem austenem commented Jan 22, 2025

Summary

Broad update to the "My Lists" feature across the portal that leverages the new UKV API.

Major updates include:

  • Lists will now persist across devices for authenticated users.
  • Lists for non-authenticated users are still stored locally; should a user log in on a device with lists stored locally, these will be copied over to that user's account. This only happens the first time they log in.
  • "Save to list" buttons are now present on all search pages and dataset tables.
  • Language on all "My Lists" pages and alerts have been updated.
  • All associated files have been converted to TypeScript.

Design Documentation/Original Tickets

CAT-754 Jira ticket

Testing

Tested using the following checklist (repeated with an authenticated and non-authenticated profile):

  • When logging in for the first time on a device with saved entities and lists, these are copied over.
    • When logging in for the first time on a device with no saved entities OR lists, these are “copied over” (meaning no change, but another login will not copy anything).
  • Create new list with title and/or description
  • Save entities
    • From search pages
    • From entity header of detail pages
    • From derived entities tables
    • From Collections dataset tables
  • Delete entities
  • Add entities to list
    • From lists page
    • From entity header of detail pages
  • Remove entities from list
    • From list detail page
    • From entity header of detail pages
  • View list detail page without entities
  • View list detail page with entities
  • Edit list title/description
  • Delete list

Screenshots/Video

Updated Search page
Screenshot 2025-01-21 at 6 11 22 PM

Updated Collections dataset table
Screenshot 2025-01-22 at 12 41 41 PM

Example of banner shown after initial transfer of lists to a user's profile
Screenshot 2025-01-21 at 6 08 28 PM

Checklist

  • Code follows the project's coding standards
    • Lint checks pass locally
    • New CHANGELOG-your-feature-name-here.md is present in the root directory, describing the change(s) in full sentences.
  • Unit tests covering the new feature have been added
  • All existing tests pass
  • Any relevant documentation in JIRA/Confluence has been updated to reflect the new feature
  • Any new functionalities have appropriate analytics functionalities added

Additional Notes

The majority of the updated files in this PR are either TypeScript conversions or updates to files that used the SavedEntitiesStore, as that store is now wrapped in a hook (useSavedLists).

Copy link
Collaborator

@john-conroy john-conroy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused why we are continuing to use a store for the saved lists/entities. Maybe it would be helpful to have a chat between the three of us?

Comment on lines +4 to +5
dateSaved: Date.now(),
dateLastModified: Date.now(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps rename these to saved_timestamp and last_modified_timestamp. I think of a date object or string when thinking of a date.

Comment on lines +33 to +56
async function fetchResponse({
url,
token,
method,
body,
}: {
url: string;
token: string;
method: 'PUT' | 'DELETE';
body?: string;
}) {
const response = await fetch(url, {
method,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body,
});

if (!response.ok) {
console.error('UKV API failed with error: ', await response.text());
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pattern used elsewhere so no fault in introducing it, but could we use the fetcher in the swr helpers?

function useSavedLists() {
const urls = useUkvApiURLs();
const { groupsToken, isAuthenticated } = useAppContext();
const { setTransferredToProfile } = useSavedListsAlertsStore();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const { setTransferredToProfile } = useSavedListsAlertsStore();
const setTransferredToProfile = useSavedListsAlertsStore((state) => setTransferredToProfile);

We should slice the store when accessing specific fields. This avoids updates when state outside of the field you're picking changes.

https://github.com/pmndrs/zustand?tab=readme-ov-file#selecting-multiple-state-slices

editListRemote,
} from 'js/components/savedLists/api';

const savedEntitiesSelector = (state: SavedEntitiesStore) => ({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a subset of the store or the entire thing? If it's the entire store we don't need the selector.

Comment on lines +84 to +85
storeHasBeenSetRef.current = true;
wasLoadingRef.current = isLoading;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need both storeHasBeenSetRef and wasLoadingRef, I believe they will always have the same value?

storeHasBeenSetRef.current = true;
wasLoadingRef.current = isLoading;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isAuthenticated, isLoading]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this to avoid putting the store into the dependencies?

Comment on lines +76 to +82
copySavedItemsToRemoteStore({ savedEntitiesLocal, savedListsLocal, urls, groupsToken });
store.setEntities(savedEntitiesLocal);
store.setLists(savedListsLocal);
} else {
// If the user already has saved entities and lists in their remote store, we need to copy those over to the local store.
store.setEntities(savedEntities);
store.setLists(savedLists);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we still using a store for the saved lists/entities. Wouldn't we be fetching this data from the API using `swr1?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants