Merge branch 'develop' of bitbucket.org:jamkazam/jam-cloud into develop
This commit is contained in:
commit
4732138cbd
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ describe('Browse sessions', () => {
|
|||
});
|
||||
|
||||
it('alerts when there is no records', () => {
|
||||
cy.contains('No Records!');
|
||||
cy.contains('There are no public, open sessions currently available for you to join');
|
||||
cy.contains('create a session').click();
|
||||
cy.url().should('include', '/sessions/new');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,26 @@ beforeEach(() => {
|
|||
statusCode: 200,
|
||||
body: [],
|
||||
}).as('getAppFeatures');
|
||||
|
||||
cy.intercept('GET', /\S+\/users\/\S+\/profile/, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: 1,
|
||||
name: 'Jane Doe',
|
||||
email: 'jane@example.com',
|
||||
},
|
||||
}).as('getUserProfile');
|
||||
|
||||
cy.intercept('GET', /\S+\/users\/\S+\/my_notifications/, {
|
||||
statusCode: 200,
|
||||
body: [],
|
||||
}).as('getMyNotifications');
|
||||
|
||||
cy.intercept('GET', /\S+\/users\/\S+\/friends/, {
|
||||
statusCode: 200,
|
||||
body: [],
|
||||
}).as('getMyFriends');
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import JKGenericNotification from './JKGenericNotification';
|
|||
import JKFriendRequestNotification from './JKFriendRequestNotification';
|
||||
import TextMessageNotification from './JKTextMessageNotification';
|
||||
import classNames from 'classnames';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
function JKNotification(props) {
|
||||
|
||||
|
|
@ -16,11 +17,8 @@ function JKNotification(props) {
|
|||
|
||||
const dispatch = useDispatch();
|
||||
const { currentUser } = useAuth()
|
||||
const handleOnAccept = () => {
|
||||
deleteNotification();
|
||||
}
|
||||
|
||||
const deleteNotification = async () => {
|
||||
|
||||
const handleOnAccept = async () => {
|
||||
const options = {
|
||||
userId: currentUser.id,
|
||||
notificationId: notification_id
|
||||
|
|
@ -29,13 +27,15 @@ function JKNotification(props) {
|
|||
await dispatch(removeNotification(options))
|
||||
.unwrap()
|
||||
.then(resp => {
|
||||
|
||||
toast.success('Friend request accepted');
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
toast.error('Error accepting friend request');
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
const NOTIFICATION_TYPES = {
|
||||
TEXT_MESSAGE: 'TEXT_MESSAGE',
|
||||
FRIEND_REQUEST: 'FRIEND_REQUEST'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { Alert, Col, Row, Card, CardBody } from 'reactstrap';
|
||||
import { Col, Row, Card, CardBody } from 'reactstrap';
|
||||
import { Link } from 'react-router-dom';
|
||||
import FalconCardHeader from '../common/FalconCardHeader';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
|
@ -53,9 +54,9 @@ function JKMusicSessions() {
|
|||
) : (
|
||||
<Row className="p-card">
|
||||
<Col>
|
||||
<Alert color="info" className="mb-0">
|
||||
{t('no_records', { ns: 'common' })}
|
||||
</Alert>
|
||||
{t('list.no_records_1', { ns: 'sessions' })}
|
||||
<Link to="/sessions/new">{t('list.create_session', { ns: 'sessions' })}</Link>
|
||||
{t('list.no_records_2', { ns: 'sessions' })}
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,10 @@
|
|||
"notes": {
|
||||
"invited": "YOU WERE INVITED TO THIS SESSION",
|
||||
"has_friend": "YOU HAVE A FRIEND IN THIS SESSION"
|
||||
}
|
||||
},
|
||||
"no_records_1": "There are no public, open sessions currently available for you to join. We suggest you ",
|
||||
"create_session": "create a session",
|
||||
"no_records_2": " that others can join now, or wait a bit and then refresh this page in your browser to see if new public sessions have been started."
|
||||
},
|
||||
"lobby": {
|
||||
"page_title": "Lobby",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -545,7 +545,7 @@ class ApiUsersController < ApiController
|
|||
limit = 20 if limit <= 0
|
||||
offset = params[:offset].to_i
|
||||
offset = 0 if offset < 0
|
||||
query = @notifications = @user.notifications.joins(:source_user)
|
||||
query = @user.notifications.joins(:source_user)
|
||||
@unread_total = query.unread.size
|
||||
@notifications = query.offset(offset).limit(limit)
|
||||
@next = @notifications.size > 0 ? offset + limit : nil
|
||||
|
|
|
|||
Loading…
Reference in New Issue