jam-ui: fix pagination in musician listing
This commit is contained in:
parent
245b39f67d
commit
ee54464cfc
|
|
@ -311,6 +311,7 @@
|
|||
"genres": []
|
||||
}
|
||||
],
|
||||
"offset": 11,
|
||||
"page_count": 2,
|
||||
"my_audio_latency": 5,
|
||||
"filter_json": "{\"id\":\"68dcc055-cb5d-40d6-8ed4-66772d1a1a31\",\"user_id\":\"27bd4a30-d1b8-4eea-8454-01a104d59381\",\"foreign_key1_id\":null,\"data_blob\":{\"sort_order\":\"latency\",\"instruments\":[],\"genres\":[],\"concert_gigs\":\"-1\",\"interests\":\"any\",\"studio_sessions\":\"-1\",\"ages\":[],\"skill_level\":\"-1\"}}",
|
||||
|
|
|
|||
|
|
@ -285,6 +285,7 @@
|
|||
"genres": []
|
||||
}
|
||||
],
|
||||
"offset": null,
|
||||
"page_count": 2,
|
||||
"my_audio_latency": 5,
|
||||
"filter_json": "{\"id\":\"68dcc055-cb5d-40d6-8ed4-66772d1a1a31\",\"user_id\":\"27bd4a30-d1b8-4eea-8454-01a104d59381\",\"foreign_key1_id\":null,\"data_blob\":{\"sort_order\":\"latency\",\"instruments\":[],\"genres\":[],\"concert_gigs\":\"-1\",\"interests\":\"any\",\"studio_sessions\":\"-1\",\"ages\":[],\"skill_level\":\"-1\"}}",
|
||||
|
|
|
|||
|
|
@ -124,15 +124,15 @@ describe('Friends page without data', () => {
|
|||
|
||||
});
|
||||
|
||||
describe('Friends page with data', () => {
|
||||
describe.only('Friends page with data', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate({ id: '2' }); //currentUser id is 2 - people.yaml fixture
|
||||
cy.intercept('POST', /\S+\/filter\?page=1/, { fixture: 'people_page1' }).as('getPeople_page1');
|
||||
cy.intercept('POST', /\S+\/filter\?page=2/, { fixture: 'people_page2' }).as('getPeople_page2');
|
||||
cy.intercept('POST', /\S+\/filter\?page=0/, { fixture: 'people_page1' }).as('getPeople_page1');
|
||||
cy.intercept('POST', /\S+\/filter\?page=1/, { fixture: 'people_page2' }).as('getPeople_page2');
|
||||
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
|
||||
});
|
||||
|
||||
describe('listing users', () => {
|
||||
describe.only('listing users', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/friends');
|
||||
});
|
||||
|
|
@ -142,6 +142,13 @@ describe('Friends page with data', () => {
|
|||
cy.viewport('macbook-13');
|
||||
});
|
||||
|
||||
it('paginate', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 10);
|
||||
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');
|
||||
});
|
||||
|
||||
it('show profiles', () => {
|
||||
cy.contains('Find New Friends').should('exist');
|
||||
cy.contains('Update Search').should('exist');
|
||||
|
|
@ -219,12 +226,7 @@ describe('Friends page with data', () => {
|
|||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('paginate', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 10);
|
||||
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');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('in mobile', () => {
|
||||
|
|
@ -276,18 +278,9 @@ describe('Friends page with data', () => {
|
|||
.should('not.contain', 'More');
|
||||
});
|
||||
|
||||
it('click more button', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=btnMore]')
|
||||
.click();
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
//it.skip('click connect button', () => {});
|
||||
|
||||
it('click connect button', () => {});
|
||||
|
||||
it('click message button', () => {});
|
||||
//it.skip('click message button', () => {});
|
||||
|
||||
it('paginate', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-button-prev').should('have.class', 'swiper-button-disabled');
|
||||
|
|
@ -297,6 +290,15 @@ describe('Friends page with data', () => {
|
|||
}
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-button-next').should('have.class', 'swiper-button-disabled');
|
||||
});
|
||||
|
||||
it('click more button', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=btnMore]')
|
||||
.click();
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -19,19 +19,23 @@ function JKPeopleFilter() {
|
|||
const { t } = useTranslation();
|
||||
const [show, setShow] = useState(false);
|
||||
const [resetFilter, setResetFilter] = useState(false);
|
||||
const [showLoadMore, setShowLoadMore] = useState(false)
|
||||
const [instruments, setInstruments] = useState([]);
|
||||
const [genres, setGenres] = useState([]);
|
||||
const dispatch = useDispatch();
|
||||
const currentPage = useRef(1);
|
||||
const nextPage = useRef(1);
|
||||
const [hasNextPage, setHasNextPage] = useState(true)
|
||||
|
||||
const currentPage = useRef(0);
|
||||
const nextPage = useRef(0);
|
||||
|
||||
const perPageLimit = 20
|
||||
|
||||
const { greaterThan } = useResponsive();
|
||||
|
||||
const peopleListRef = useRef();
|
||||
|
||||
const people = useSelector(state => state.people.people);
|
||||
const totalPages = useSelector(state => state.people.totalPages);
|
||||
const hasNextPage = useSelector(state => state.people.hasNextPage);
|
||||
//const offset = useSelector(state => state.people.offset);
|
||||
const loadingStatus = useSelector(state => state.people.status);
|
||||
|
||||
const { register, handleSubmit, setValue, getValues, control } = useForm({
|
||||
|
|
@ -113,7 +117,7 @@ function JKPeopleFilter() {
|
|||
};
|
||||
|
||||
const goNextPage = () => {
|
||||
submitPageQuery(currentPage.current)
|
||||
submitPageQuery()
|
||||
};
|
||||
|
||||
const clearFilterOpts = () => {
|
||||
|
|
@ -136,13 +140,18 @@ function JKPeopleFilter() {
|
|||
|
||||
const submitForm = event => {
|
||||
event.preventDefault();
|
||||
currentPage.current = 1;
|
||||
nextPage.current = 1;
|
||||
currentPage.current = 0;
|
||||
nextPage.current = 0;
|
||||
dispatch(resetState());
|
||||
handleSubmit(onSubmit)(nextPage.current);
|
||||
handleSubmit(onSubmit)();
|
||||
setShow(false);
|
||||
};
|
||||
|
||||
|
||||
const isBeforeSecondPageLoad = () => {
|
||||
return currentPage.current === 0 && nextPage.current === 1
|
||||
}
|
||||
|
||||
const onSubmit = (data) => {
|
||||
let genres = [];
|
||||
let joined_within_days = '';
|
||||
|
|
@ -165,12 +174,12 @@ function JKPeopleFilter() {
|
|||
|
||||
currentPage.current = nextPage.current
|
||||
|
||||
dispatch(fetchPeople({ data: params, page: currentPage.current }));
|
||||
|
||||
|
||||
dispatch(fetchPeople({ data: params, page: currentPage.current, limit: perPageLimit }));
|
||||
nextPage.current = currentPage.current + 1
|
||||
|
||||
if (hasNextPage) {
|
||||
dispatch(preFetchPeople({ data: params, page: nextPage.current }));
|
||||
if (hasNextPage || isBeforeSecondPageLoad()) { //reason for isBeforeSecondPageLoad(): after the first fetchPeople() there is a possibility that hasNextPage may not been sat in redux store.
|
||||
dispatch(preFetchPeople({ data: params, page: nextPage.current, limit: perPageLimit }));
|
||||
nextPage.current = nextPage.current + 1;
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -181,36 +190,38 @@ function JKPeopleFilter() {
|
|||
useEffect(() => {
|
||||
fetchGenres();
|
||||
fetchInstruments();
|
||||
submitPageQuery(currentPage.current)
|
||||
currentPage.current = 0
|
||||
submitPageQuery()
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if(totalPages > 0){
|
||||
setHasNextPage(currentPage.current < totalPages)
|
||||
}
|
||||
}, [totalPages, currentPage.current]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (resetFilter) {
|
||||
clearFilterOpts();
|
||||
dispatch(resetState());
|
||||
currentPage.current = 1;
|
||||
nextPage.current = 1;
|
||||
currentPage.current = 0;
|
||||
nextPage.current = 0;
|
||||
handleSubmit(onSubmit)();
|
||||
setResetFilter(false);
|
||||
}
|
||||
}, [resetFilter]);
|
||||
|
||||
useEffect(() => {
|
||||
if(loadingStatus === 'succeeded' && people.length === 0 && currentPage.current === 1 && !getValues("from_location")){
|
||||
//no results found. let's fetch again with from_location enabled
|
||||
setValue('from_location', true);
|
||||
nextPage.current = 1
|
||||
currentPage.current = 1
|
||||
submitPageQuery()
|
||||
setShowLoadMore(hasNextPage)
|
||||
if(loadingStatus === 'succeeded'){
|
||||
|
||||
if(people.length === 0 && currentPage.current === 0 && !getValues("from_location")){
|
||||
//no results found. let's fetch again with from_location enabled
|
||||
setValue('from_location', true);
|
||||
nextPage.current = 0
|
||||
currentPage.current = 0
|
||||
submitPageQuery()
|
||||
}
|
||||
}
|
||||
|
||||
}, [loadingStatus])
|
||||
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<FalconCardHeader title={t('page_title', { ns: 'people' })} titleClass="font-weight-bold">
|
||||
|
|
@ -419,7 +430,7 @@ function JKPeopleFilter() {
|
|||
<JKPeopleList
|
||||
people={people}
|
||||
goNextPage={goNextPage}
|
||||
hasNext={hasNextPage}
|
||||
hasNext={showLoadMore}
|
||||
isLoading={loadingStatus === 'loading' && people.length !== 0}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ const JKPeopleList = ({ people, goNextPage, hasNext, isLoading }) => {
|
|||
))}
|
||||
</tbody>
|
||||
</Table>
|
||||
|
||||
|
||||
|
||||
{hasNext && (
|
||||
<Button color="primary" outline={true} onClick={() => goNextPage()} disabled={isLoading} data-testid="paginate-next-page">
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ export const getPersonById = (id) => {
|
|||
))
|
||||
}
|
||||
|
||||
export const getPeople = ({ data, page } = {}) => {
|
||||
export const getPeople = ({ data, page, limit } = {}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
apiFetch(`/filter?page=${page}`, {
|
||||
apiFetch(`/filter?page=${page}&limit=${limit}`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ const initialState = {
|
|||
status: 'idel',
|
||||
error: null,
|
||||
totalPages: 0,
|
||||
hasNextPage: false
|
||||
}
|
||||
|
||||
export const fetchPeople = createAsyncThunk(
|
||||
|
|
@ -68,7 +69,10 @@ export const peopleSlice = createSlice({
|
|||
},
|
||||
loadPrefetched: (state, action) => {
|
||||
if(state.prefetched.length > 0){
|
||||
state.people = [...state.people, ...state.prefetched]
|
||||
const records = new Set([...state.people, ...state.prefetched]);
|
||||
const unique = [];
|
||||
records.map(x => unique.filter(a => a.id === x.id).length > 0 ? null : unique.push(x))
|
||||
state.people = unique
|
||||
}
|
||||
state.prefetched = []
|
||||
}
|
||||
|
|
@ -79,23 +83,33 @@ export const peopleSlice = createSlice({
|
|||
state.status = 'loading'
|
||||
})
|
||||
.addCase(fetchPeople.fulfilled, (state, action) => {
|
||||
console.log("DEBUG: fetchPeople action.payload", action.payload);
|
||||
//console.log("DEBUG: action.meta.arg", action.meta.arg);
|
||||
const records = new Set([...state.people, ...action.payload.musicians]);
|
||||
const unique = [];
|
||||
records.map(x => unique.filter(a => a.id === x.id).length > 0 ? null : unique.push(x))
|
||||
state.people = unique
|
||||
state.totalPages = action.payload.page_count
|
||||
state.hasNextPage = action.payload.offset && parseInt(action.payload.offset) > 0
|
||||
state.status = 'succeeded'
|
||||
})
|
||||
.addCase(fetchPeople.rejected, (state, action) => {
|
||||
state.status = 'failed'
|
||||
state.error = action.error.message
|
||||
})
|
||||
.addCase(preFetchPeople.pending, (state, action) => {
|
||||
})
|
||||
.addCase(preFetchPeople.fulfilled, (state, action) => {
|
||||
state.prefetched = action.payload.musicians
|
||||
console.log("DEBUG: preFetchPeople action.payload", action.payload);
|
||||
const records = new Set([...state.prefetched, ...action.payload.musicians]);
|
||||
const unique = [];
|
||||
records.map(x => unique.filter(a => a.id === x.id).length > 0 ? null : unique.push(x))
|
||||
state.prefetched = unique
|
||||
state.hasNextPage = action.payload.offset && parseInt(action.payload.offset) > 0
|
||||
})
|
||||
.addCase(preFetchPeople.rejected, (state, action) => {
|
||||
})
|
||||
.addCase(acceptFriendRequest.fulfilled, (state, action) => {
|
||||
|
||||
})
|
||||
.addCase(fetchPerson.fulfilled, (state, action) => {
|
||||
const person = state.people.find(person => person.id === action.payload.id)
|
||||
|
|
|
|||
|
|
@ -200,6 +200,12 @@ module JamRuby
|
|||
rel
|
||||
end
|
||||
|
||||
def user_search_results(user_ids)
|
||||
rel = do_filter(user_ids)
|
||||
rel = self.search_includes(rel)
|
||||
process_results_page(rel.all)
|
||||
end
|
||||
|
||||
def search_results_page(filter=nil, page=1, user_ids=nil)
|
||||
if filter
|
||||
self.data_blob = filter
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ module JamRuby
|
|||
#NOTE: we can change to this once we upgrade postgresql
|
||||
#rel = rel.where(id: user_ids).where('users.id <> ?', self.user.id).order("array_position(ARRAY[#{user_ids.map { |i| "'#{i}'" }.join(',')}], id::TEXT)")
|
||||
|
||||
rel = self._sort_by_ids_ordinality(rel, user_ids)
|
||||
#rel = self._sort_by_ids_ordinality(rel, user_ids)
|
||||
end
|
||||
end
|
||||
rel
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ class ApiSearchController < ApiController
|
|||
latency_good = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_good])
|
||||
latency_fair = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_fair])
|
||||
latency_high = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_high])
|
||||
page = [params[:page].to_i, 1].max
|
||||
limit = 20
|
||||
page = [params[:page].to_i, 0].max
|
||||
limit = [params[:limit].to_i, 20].max
|
||||
filter_params = {}
|
||||
|
||||
filter_params.merge!(from_location: params[:from_location] ? '1' : '0')
|
||||
|
|
@ -143,7 +143,10 @@ class ApiSearchController < ApiController
|
|||
begin
|
||||
|
||||
#bm = Benchmark.measure do
|
||||
@latency_data = users_latency_data(latency_good, latency_fair, latency_high, filter_params, page, limit)
|
||||
result = users_latency_data(latency_good, latency_fair, latency_high, filter_params, page, limit)
|
||||
@latency_data = result[:data]
|
||||
@offset = result[:offset]
|
||||
|
||||
user_ids = @latency_data.map{ |l_data| l_data[:user_id] }
|
||||
|
||||
#end
|
||||
|
|
@ -154,7 +157,8 @@ class ApiSearchController < ApiController
|
|||
# end if Rails.env.production?
|
||||
|
||||
sobj = MusicianSearch.user_search_filter(current_user)
|
||||
@search = sobj.search_results_page(filter_params, page, user_ids)
|
||||
#@search = sobj.search_results_page(filter_params, page, user_ids)
|
||||
@search = sobj.user_search_results(user_ids)
|
||||
|
||||
respond_with @search, responder: ApiResponder, status: 201, template: 'api_search/filter'
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ module LatencyHelper
|
|||
};
|
||||
|
||||
def users_latency_data(latency_good, latency_fair, latency_high, filter_opts, page, limit)
|
||||
|
||||
latency_data = []
|
||||
|
||||
uri = URI(filter_latency_url)
|
||||
|
|
@ -21,13 +22,15 @@ module LatencyHelper
|
|||
req["Authorization"] = "Basic #{Rails.application.config.latency_data_host_auth_code}"
|
||||
req["Content-Type"] = "application/json"
|
||||
|
||||
offset = page.to_i <= 1 ? 0 : ((page.to_i - 1) * limit) + 1
|
||||
|
||||
req_params = {
|
||||
my_user_id: current_user.id,
|
||||
my_public_ip: request.remote_ip,
|
||||
my_device_id: nil,
|
||||
my_client_id: nil,
|
||||
from_location: filter_opts[:from_location] || "0",
|
||||
offset: page,
|
||||
offset: offset,
|
||||
limit: limit
|
||||
}
|
||||
|
||||
|
|
@ -39,9 +42,13 @@ module LatencyHelper
|
|||
req.body = req_params.to_json
|
||||
|
||||
response = http.request(req)
|
||||
|
||||
#debugger
|
||||
|
||||
if response.is_a?(Net::HTTPOK) || response.is_a?(Net::HTTPSuccess)
|
||||
graph_db_users = JSON.parse(response.body)["users"]
|
||||
json_body = JSON.parse(response.body)
|
||||
graph_db_users = json_body['users']
|
||||
offset = json_body['next']
|
||||
|
||||
if latency_good || latency_fair || latency_high
|
||||
#fiter by latency params
|
||||
|
|
@ -62,7 +69,7 @@ module LatencyHelper
|
|||
}
|
||||
}.uniq
|
||||
|
||||
return latency_data
|
||||
return {data: latency_data, offset: offset}
|
||||
else
|
||||
logger.debug("Latency response failed: #{response}")
|
||||
Bugsnag.notify("LatencyResponseFailed") do |report|
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
object @search
|
||||
|
||||
node :page_count do |foo|
|
||||
@search.page_count
|
||||
node :offset do
|
||||
@offset
|
||||
end
|
||||
|
||||
# node :page_count do |foo|
|
||||
# @search.page_count
|
||||
# end
|
||||
|
||||
node :my_audio_latency do |user|
|
||||
current_user.last_jam_audio_latency.round if current_user.last_jam_audio_latency
|
||||
end
|
||||
|
|
|
|||
|
|
@ -215,13 +215,11 @@ describe "Musician Filter API", type: :request do
|
|||
end
|
||||
|
||||
it "filter musicians by days ago that they joined" do
|
||||
pending
|
||||
post '/api/filter.json', { latency_good: true, latency_fair: true, latency_high: true, joined_within_days: 1 }
|
||||
expect(JSON.parse(response.body)["musicians"].size).to eq(2)
|
||||
end
|
||||
|
||||
it "finds user updated_at is within a day ago" do
|
||||
pending
|
||||
post '/api/filter.json', { latency_good: true, latency_fair: true, latency_high: true, active_within_days: 1 }
|
||||
expect(JSON.parse(response.body)["musicians"].size).to eq(1)
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue