diff --git a/jam-ui/cypress/e2e/friends/friends-page.cy.js b/jam-ui/cypress/e2e/friends/friends-page.cy.js index e9b6bcc9f..5985c2856 100644 --- a/jam-ui/cypress/e2e/friends/friends-page.cy.js +++ b/jam-ui/cypress/e2e/friends/friends-page.cy.js @@ -99,6 +99,10 @@ describe('Friends page with data', () => { cy.intercept('POST', /\S+\/filter\?offset=10/, { fixture: 'people_page2' }).as('getPeople_page2'); cy.intercept('POST', /\S+\/filter\?offset=20/, { fixture: 'people_page3' }).as('getPeople_page3'); cy.intercept('GET', /\S+\/profile/, { fixture: 'person' }); + cy.intercept('GET', /\S+\/my_notifications\S+/, { + statusCode: 200, + body: [] + }); }); describe('listing users', () => { @@ -116,7 +120,6 @@ describe('Friends page with data', () => { cy.wait('@getPeople_page2') cy.get('[data-testid=paginate-next-page]').click(); cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 20); - //cy.get('[data-testid=paginate-next-page]').should('not.exist'); cy.get('[data-testid=paginate-next-page]').click(); cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 30); cy.get('[data-testid=paginate-next-page]').should('not.exist'); diff --git a/jam-ui/src/components/page/JKPeopleFilter.js b/jam-ui/src/components/page/JKPeopleFilter.js index 3bf8f6ba7..f24769b30 100644 --- a/jam-ui/src/components/page/JKPeopleFilter.js +++ b/jam-ui/src/components/page/JKPeopleFilter.js @@ -14,7 +14,7 @@ import JKPeopleSwiper from './JKPeopleSwiper'; import { getGenres, getInstruments } from '../../helpers/rest'; import { useForm, Controller, useFormState } from 'react-hook-form'; import { useDispatch, useSelector } from 'react-redux'; -import { fetchPeople, resetState, loadPrefetched, preFetchPeople } from '../../store/features/peopleSlice'; +import { fetchPeople, resetState, loadPrefetched, preFetchPeople } from '../../store/features/musiciansSlice'; function JKPeopleFilter() { const { t } = useTranslation(); @@ -35,11 +35,10 @@ function JKPeopleFilter() { const peopleListRef = useRef(); - const people = useSelector(state => state.people.people); - //const hasOffset = useSelector(state => state.people.hasOffset); - const offset = useSelector(state => state.people.offset); - const loadingStatus = useSelector(state => state.people.status); - const prefetched = useSelector(state => state.people.prefetched) + const people = useSelector(state => state.musician.people); + const offset = useSelector(state => state.musician.offset); + const loadingStatus = useSelector(state => state.musician.status); + const prefetched = useSelector(state => state.musician.prefetched) const { register, handleSubmit, setValue, getValues, control } = useForm({ defaultValues: { diff --git a/jam-ui/src/store/features/musiciansSlice.js b/jam-ui/src/store/features/musiciansSlice.js new file mode 100644 index 000000000..796b35540 --- /dev/null +++ b/jam-ui/src/store/features/musiciansSlice.js @@ -0,0 +1,166 @@ +import { createSlice, createAsyncThunk } from "@reduxjs/toolkit" +import { getPeople, getPeopleByIds, getPersonById, acceptFriendRequest as accept } from '../../helpers/rest'; + +const initialState = { + people: [], + prefetched: [], + status: 'idel', + error: null, + hasOffset: false, + offset: 0 +} + +export const fetchPeople = createAsyncThunk( + 'musician/fetchPeople', + async (options, thunkAPI) => { + const response = await getPeople(options) + return response.json() + } +) + +export const preFetchPeople = createAsyncThunk( + 'musician/preFetchPeople', + async (options, thunkAPI) => { + const response = await getPeople(options) + return response.json() + } +) + +export const fetchPeopleByIds = createAsyncThunk( + 'musician/fetchPeopleByIds', + async (options, thunkAPI) => { + const response = await getPeopleByIds(options) + return response.json() + } +) + +export const fetchPerson = createAsyncThunk( + 'musician/fetchPerson', + async (options, thunkAPI) => { + const {userId} = options + const response = await getPersonById(userId) + return response.json() + } + ,{ + condition: (options, {getState, extra}) => { + const {people} = getState() + const {userId} = options + const person = people.people.find(person => person.id === userId) + if(person && person.website){ + //only proceed if full data set for user has not been fetched. person.website is not included in the initial data fetching (i.e: in friends listing ). + return false; + } + } + } +) + +export const acceptFriendRequest = createAsyncThunk( + 'musician/acceptFriendRequest', + async(options) => { + const { userId, ...rest } = options + const response = await accept(userId, rest) + return response.json() + } +) + +export const musicianSlice = createSlice({ + name: 'musician', + initialState, + reducers: { + add: (state, action) => { + state.people.push(action.payload) + }, + resetState: (state) => { + return { ...initialState } + }, + loadPrefetched: (state, action) => { + if(state.prefetched.length > 0){ + const records = [...state.people, ...state.prefetched]; + state.people = records; + } + state.prefetched = [] + } + }, + extraReducers: (builder) => { + builder + .addCase(fetchPeople.pending, (state, action) => { + state.status = 'loading' + }) + .addCase(fetchPeople.fulfilled, (state, action) => { + // const records = [...state.people, ...action.payload.musicians]; + // state.people = records + // state.hasOffset = !!action.payload.offset + // state.offset = action.payload.offset + // state.status = 'succeeded' + //--- + const records = new Set([...state.people, ...action.payload.musicians]); + const unique = []; + records.map(x => unique.filter(p => p.id === x.id).length > 0 ? null : unique.push(x)) + state.people = unique + state.hasOffset = !!action.payload.offset + state.offset = action.payload.offset + state.status = 'succeeded' + }) + .addCase(fetchPeople.rejected, (state, action) => { + state.status = 'failed' + state.error = action.error.message + }) + .addCase(preFetchPeople.pending, (state, action) => { + state.status = 'loading' + }) + .addCase(preFetchPeople.fulfilled, (state, action) => { + // const records = [...state.prefetched, ...action.payload.musicians]; + // state.prefetched = records + // state.hasOffset = !!action.payload.offset + // state.offset = action.payload.offset + // state.status = 'succeeded' + //--- + const records = new Set([...state.prefetched, ...action.payload.musicians]); + const unique = []; + records.map(x => unique.filter(p => p.id === x.id).length > 0 ? null : unique.push(x)) + state.people = unique + state.hasOffset = !!action.payload.offset + state.offset = action.payload.offset + state.status = 'succeeded' + }) + .addCase(preFetchPeople.rejected, (state, action) => { + state.error = action.error.message + state.status = 'failed' + }) + .addCase(acceptFriendRequest.fulfilled, (state, action) => { + }) + .addCase(fetchPerson.fulfilled, (state, action) => { + const person = state.people.find(person => person.id === action.payload.id) + if(person){ + const updated = { + ...person, + ...action.payload + } + const objIndex = state.people.findIndex((p => p.id === updated.id)); + state.people[objIndex] = updated + }else{ + state.people.push(action.payload) + } + }) + .addCase(fetchPeopleByIds.pending, (state, action) => { + state.status = 'loading' + }) + .addCase(fetchPeopleByIds.fulfilled, (state, action) => { + const records = new Set([...state.people, ...action.payload.musicians]); + const unique = []; + records.map(x => unique.filter(p => p.id === x.id).length > 0 ? null : unique.push(x)) + state.people = unique + state.status = 'succeeded' + }) + .addCase(fetchPeopleByIds.rejected, (state, action) => { + state.error = action.error.message + state.status = 'failed' + }) + } +}) + +export const selectPersonById = (state, userId) => state.people.find((person) => person.id === userId) + +export const { add, resetState, loadPrefetched } = musicianSlice.actions; + +export default musicianSlice.reducer; \ No newline at end of file diff --git a/jam-ui/src/store/features/peopleSlice.js b/jam-ui/src/store/features/peopleSlice.js index f73ca694f..dff91a503 100644 --- a/jam-ui/src/store/features/peopleSlice.js +++ b/jam-ui/src/store/features/peopleSlice.js @@ -1,30 +1,31 @@ import { createSlice, createAsyncThunk } from "@reduxjs/toolkit" -import { getPeople, getPeopleByIds, getPersonById, acceptFriendRequest as accept } from '../../helpers/rest'; +//import { getPeople, getPeopleByIds, getPersonById, acceptFriendRequest as accept } from '../../helpers/rest'; +import { getPeopleByIds, getPersonById, acceptFriendRequest as accept } from '../../helpers/rest'; const initialState = { people: [], - prefetched: [], + //prefetched: [], status: 'idel', error: null, hasOffset: false, offset: 0 } -export const fetchPeople = createAsyncThunk( - 'people/fetchPeople', - async (options, thunkAPI) => { - const response = await getPeople(options) - return response.json() - } -) +// export const fetchPeople = createAsyncThunk( +// 'people/fetchPeople', +// async (options, thunkAPI) => { +// const response = await getPeople(options) +// return response.json() +// } +// ) -export const preFetchPeople = createAsyncThunk( - 'people/preFetchPeople', - async (options, thunkAPI) => { - const response = await getPeople(options) - return response.json() - } -) +// export const preFetchPeople = createAsyncThunk( +// 'people/preFetchPeople', +// async (options, thunkAPI) => { +// const response = await getPeople(options) +// return response.json() +// } +// ) export const fetchPeopleByIds = createAsyncThunk( 'people/fetchPeopleByIds', @@ -73,60 +74,60 @@ export const peopleSlice = createSlice({ resetState: (state) => { return { ...initialState } }, - loadPrefetched: (state, action) => { - if(state.prefetched.length > 0){ - const records = [...state.people, ...state.prefetched]; - state.people = records; - } - state.prefetched = [] - } + // loadPrefetched: (state, action) => { + // if(state.prefetched.length > 0){ + // const records = [...state.people, ...state.prefetched]; + // state.people = records; + // } + // state.prefetched = [] + // } }, extraReducers: (builder) => { builder - .addCase(fetchPeople.pending, (state, action) => { - state.status = 'loading' - }) - .addCase(fetchPeople.fulfilled, (state, action) => { - // const records = [...state.people, ...action.payload.musicians]; - // state.people = records - // state.hasOffset = !!action.payload.offset - // state.offset = action.payload.offset - // state.status = 'succeeded' - //--- - const records = new Set([...state.people, ...action.payload.musicians]); - const unique = []; - records.map(x => unique.filter(p => p.id === x.id).length > 0 ? null : unique.push(x)) - state.people = unique - state.hasOffset = !!action.payload.offset - state.offset = action.payload.offset - state.status = 'succeeded' - }) - .addCase(fetchPeople.rejected, (state, action) => { - state.status = 'failed' - state.error = action.error.message - }) - .addCase(preFetchPeople.pending, (state, action) => { - state.status = 'loading' - }) - .addCase(preFetchPeople.fulfilled, (state, action) => { - // const records = [...state.prefetched, ...action.payload.musicians]; - // state.prefetched = records - // state.hasOffset = !!action.payload.offset - // state.offset = action.payload.offset - // state.status = 'succeeded' - //--- - const records = new Set([...state.prefetched, ...action.payload.musicians]); - const unique = []; - records.map(x => unique.filter(p => p.id === x.id).length > 0 ? null : unique.push(x)) - state.people = unique - state.hasOffset = !!action.payload.offset - state.offset = action.payload.offset - state.status = 'succeeded' - }) - .addCase(preFetchPeople.rejected, (state, action) => { - state.error = action.error.message - state.status = 'failed' - }) + // .addCase(fetchPeople.pending, (state, action) => { + // state.status = 'loading' + // }) + // .addCase(fetchPeople.fulfilled, (state, action) => { + // // const records = [...state.people, ...action.payload.musicians]; + // // state.people = records + // // state.hasOffset = !!action.payload.offset + // // state.offset = action.payload.offset + // // state.status = 'succeeded' + // //--- + // const records = new Set([...state.people, ...action.payload.musicians]); + // const unique = []; + // records.map(x => unique.filter(p => p.id === x.id).length > 0 ? null : unique.push(x)) + // state.people = unique + // state.hasOffset = !!action.payload.offset + // state.offset = action.payload.offset + // state.status = 'succeeded' + // }) + // .addCase(fetchPeople.rejected, (state, action) => { + // state.status = 'failed' + // state.error = action.error.message + // }) + // .addCase(preFetchPeople.pending, (state, action) => { + // state.status = 'loading' + // }) + // .addCase(preFetchPeople.fulfilled, (state, action) => { + // // const records = [...state.prefetched, ...action.payload.musicians]; + // // state.prefetched = records + // // state.hasOffset = !!action.payload.offset + // // state.offset = action.payload.offset + // // state.status = 'succeeded' + // //--- + // const records = new Set([...state.prefetched, ...action.payload.musicians]); + // const unique = []; + // records.map(x => unique.filter(p => p.id === x.id).length > 0 ? null : unique.push(x)) + // state.people = unique + // state.hasOffset = !!action.payload.offset + // state.offset = action.payload.offset + // state.status = 'succeeded' + // }) + // .addCase(preFetchPeople.rejected, (state, action) => { + // state.error = action.error.message + // state.status = 'failed' + // }) .addCase(acceptFriendRequest.fulfilled, (state, action) => { }) .addCase(fetchPerson.fulfilled, (state, action) => { @@ -161,6 +162,6 @@ export const peopleSlice = createSlice({ export const selectPersonById = (state, userId) => state.people.find((person) => person.id === userId) -export const { add, resetState, loadPrefetched } = peopleSlice.actions; +export const { add, resetState } = peopleSlice.actions; export default peopleSlice.reducer; \ No newline at end of file diff --git a/jam-ui/src/store/store.js b/jam-ui/src/store/store.js index fec3b7ad5..07bf6d9f9 100644 --- a/jam-ui/src/store/store.js +++ b/jam-ui/src/store/store.js @@ -2,6 +2,7 @@ import { configureStore } from "@reduxjs/toolkit" import textMessageReducer from "./features/textMessagesSlice" import lobbyChatMessagesReducer from "./features/lobbyChatMessagesSlice" import peopleReducer from "./features/peopleSlice" +import MusicianReducer from "./features/musiciansSlice" import onlineMusicianReducer from "./features/onlineMusiciansSlice" import sessionReducer from "./features/sessionsSlice" import notificationReducer from './features/notificationSlice' @@ -15,6 +16,7 @@ export default configureStore({ reducer: { textMessage: textMessageReducer, people: peopleReducer, + musician: MusicianReducer, notification: notificationReducer, session: sessionReducer, // this is the slice that holds the currently active sessions latency: latencyReducer,