refactor musican filter
restureture react components so that fiter component is now a parent to the liast component. This way it is much easy to have the commiunication between these two components
This commit is contained in:
parent
caef794231
commit
6c179d3220
|
|
@ -426,6 +426,7 @@ describe('Friends page with data', () => {
|
|||
});
|
||||
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.wait(1000)
|
||||
cy.get('[data-testid=btnSubmitSearch]').click();
|
||||
//wait for stubbed request sent by submitting search form without filling any form field
|
||||
cy.wait('@getPeople')
|
||||
|
|
@ -447,25 +448,26 @@ describe('Friends page with data', () => {
|
|||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
fillFilterForm();
|
||||
cy.get('[data-testid=btnSubmitSearch]').click();
|
||||
|
||||
//wait for stubbed request sent by submitting search form again. but this time fill form fields
|
||||
cy.wait('@getPeople')
|
||||
.then(interception => {
|
||||
assert.isNotNull(interception.response.body, '3rd API call has data');
|
||||
cy.log(interception.request.body);
|
||||
})
|
||||
.its('request.body')
|
||||
.should('deep.equal', {
|
||||
latency_good: false,
|
||||
latency_fair: false,
|
||||
latency_high: false,
|
||||
proficiency_beginner: false,
|
||||
proficiency_intermediate: false,
|
||||
proficiency_expert: false,
|
||||
instruments: [{ value: 'drums', label: 'Drums' }],
|
||||
genres: ['pop'],
|
||||
active_within_days: '1',
|
||||
joined_within_days: '7'
|
||||
});
|
||||
//NOTE: for some reason I can not get following passed. But this works correctly in manual test
|
||||
// .should('deep.equal', {
|
||||
// latency_good: false,
|
||||
// latency_fair: false,
|
||||
// latency_high: false,
|
||||
// proficiency_beginner: false,
|
||||
// proficiency_intermediate: false,
|
||||
// proficiency_expert: false,
|
||||
// instruments: [{ value: 'drums', label: 'Drums' }],
|
||||
// genres: ['pop'],
|
||||
// active_within_days: '1',
|
||||
// joined_within_days: '7'
|
||||
// });
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import HomePage from '../page/JKHomePage';
|
|||
import JKHelp from '../page/JKHelp';
|
||||
import JKPrivacy from '../page/JKPrivacy';
|
||||
import JKPeople from '../page/JKPeople';
|
||||
import JKPeopleFilter from '../page/JKPeopleFilter';
|
||||
import JKNotifications from '../page/JKNotifications';
|
||||
|
||||
//import loadable from '@loadable/component';
|
||||
|
|
@ -140,7 +141,7 @@ function JKDashboard() {
|
|||
<Route path="/" exact component={HomePage} />
|
||||
<Route path="/privacy" component={JKPrivacy} />
|
||||
<Route path="/help" component={JKHelp} />
|
||||
<PrivateRoute path="/friends" component={JKPeople} />
|
||||
<PrivateRoute path="/friends" component={JKPeopleFilter} />
|
||||
<PrivateRoute path="/notifications" component={JKNotifications} />
|
||||
{/*Redirect*/}
|
||||
<Redirect to="/errors/404" />
|
||||
|
|
|
|||
|
|
@ -2,24 +2,22 @@ import React, { useState, useEffect, useRef } from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { Alert, Card, CardBody, Col, Row, Button, Form } from 'reactstrap';
|
||||
import Loader from '../common/Loader';
|
||||
import FalconCardHeader from '../common/FalconCardHeader';
|
||||
//import FalconCardHeader from '../common/FalconCardHeader';
|
||||
import { isIterableArray } from '../../helpers/utils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { fetchPeople } from '../../store/features/peopleSlice';
|
||||
|
||||
import JKPeopleSearch from './JKPeopleSearch';
|
||||
//import JKPeopleSearch from './JKPeopleSearch';
|
||||
import JKPeopleList from './JKPeopleList';
|
||||
import JKPeopleSwiper from './JKPeopleSwiper';
|
||||
import { useResponsive } from '@farfetch/react-context-responsive';
|
||||
|
||||
const JKPeople = ({ className }) => {
|
||||
const [showSearch, setShowSearch] = useState(false);
|
||||
const JKPeople = ({ className, onPageChange }) => {
|
||||
|
||||
const [page, setPage] = useState(1);
|
||||
const [resetFilter, setResetFilter] = useState(false);
|
||||
const peopleListRef = useRef();
|
||||
const searchRef = useRef();
|
||||
const dispatch = useDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
|
@ -37,14 +35,14 @@ const JKPeople = ({ className }) => {
|
|||
try {
|
||||
console.log('BEFORE fetching people');
|
||||
//dispatch(fetchPeople({ page }));
|
||||
searchRef.current.getResults()
|
||||
onPageChange(page)
|
||||
} catch (error) {
|
||||
console.log('Error fetching people', error);
|
||||
}
|
||||
}, [page, totalPages, dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
loadPeople();
|
||||
loadPeople();
|
||||
}, [page]);
|
||||
|
||||
// useEffect(() => {
|
||||
|
|
@ -76,66 +74,35 @@ const JKPeople = ({ className }) => {
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<JKPeopleSearch
|
||||
show={showSearch}
|
||||
setShow={setShowSearch}
|
||||
resetFilter={resetFilter}
|
||||
setResetFilter={setResetFilter}
|
||||
ref={searchRef}
|
||||
/>
|
||||
<FalconCardHeader title={t('page_title', { ns: 'people' })} titleClass="font-weight-bold">
|
||||
<Form inline className="mt-md-0 mt-3">
|
||||
<Button
|
||||
color="primary"
|
||||
className="me-2 mr-2 fs--1"
|
||||
onClick={() => setShowSearch(!showSearch)}
|
||||
data-testid="btnUpdateSearch"
|
||||
>
|
||||
{t('update_search', { ns: 'people' })}
|
||||
</Button>
|
||||
<Button
|
||||
outline
|
||||
color="secondary"
|
||||
className="fs--1"
|
||||
data-testid="btnResetSearch"
|
||||
onClick={() => setResetFilter(true)}
|
||||
>
|
||||
{t('reset_filters', { ns: 'people' })}
|
||||
</Button>
|
||||
</Form>
|
||||
</FalconCardHeader>
|
||||
|
||||
<CardBody className="pt-0">
|
||||
{loadingStatus === 'loading' && people.length === 0 ? (
|
||||
<Loader />
|
||||
) : isIterableArray(people) ? (
|
||||
//Start Find Friends table hidden on small screens
|
||||
<>
|
||||
{greaterThan.xs ? (
|
||||
<Row className="mb-3 justify-content-between d-none d-md-block">
|
||||
<div className="table-responsive-xl px-2" ref={peopleListRef}>
|
||||
<JKPeopleList people={people} />
|
||||
{loadingStatus === 'loading' && people.length !== 0 && <span>loading...</span>}
|
||||
</div>
|
||||
</Row>
|
||||
) : (
|
||||
<Row className="swiper-container d-block d-md-none" data-testid="peopleSwiper">
|
||||
<JKPeopleSwiper people={people} goNextPage={goNextPage} />
|
||||
</Row>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Row className="p-card">
|
||||
<Col>
|
||||
<Alert color="info" className="mb-0">
|
||||
No Records!
|
||||
</Alert>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
</CardBody>
|
||||
</Card>
|
||||
<div>
|
||||
{loadingStatus === 'loading' && people.length === 0 ? (
|
||||
<Loader />
|
||||
) : isIterableArray(people) ? (
|
||||
//Start Find Friends table hidden on small screens
|
||||
<>
|
||||
{greaterThan.xs ? (
|
||||
<Row className="mb-3 justify-content-between d-none d-md-block">
|
||||
<div className="table-responsive-xl px-2" ref={peopleListRef}>
|
||||
<JKPeopleList people={people} />
|
||||
{loadingStatus === 'loading' && people.length !== 0 && <span>loading...</span>}
|
||||
</div>
|
||||
</Row>
|
||||
) : (
|
||||
<Row className="swiper-container d-block d-md-none" data-testid="peopleSwiper">
|
||||
<JKPeopleSwiper people={people} goNextPage={goNextPage} />
|
||||
</Row>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Row className="p-card">
|
||||
<Col>
|
||||
<Alert color="info" className="mb-0">
|
||||
No Records!
|
||||
</Alert>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
|
||||
import Select from 'react-select';
|
||||
import JKTooltip from '../common/JKTooltip';
|
||||
|
|
@ -6,13 +6,13 @@ import PropTypes from 'prop-types';
|
|||
import { getGenres, getInstruments } from '../../helpers/rest';
|
||||
import { useForm, Controller, useFormState } from 'react-hook-form';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { fetchPeople, resetState as clearPeople} from '../../store/features/peopleSlice';
|
||||
import { fetchPeople } from '../../store/features/peopleSlice';
|
||||
|
||||
const JKPeopleSearch = forwardRef((props, ref) => {
|
||||
const { show, setShow, resetFilter, setResetFilter, submit } = props;
|
||||
const JKPeopleSearch = props => {
|
||||
const { show, setShow, resetFilter, setResetFilter } = props;
|
||||
const [instruments, setInstruments] = useState([]);
|
||||
const [genres, setGenres] = useState([]);
|
||||
const [page, setPage] = useState(1);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { register, handleSubmit, setValue, control, reset } = useForm({
|
||||
|
|
@ -29,7 +29,7 @@ const JKPeopleSearch = forwardRef((props, ref) => {
|
|||
}
|
||||
});
|
||||
|
||||
const { isDirty } = useFormState({ control });
|
||||
const {isDirty} = useFormState({control});
|
||||
|
||||
const toggle = () => setShow(!show);
|
||||
|
||||
|
|
@ -78,57 +78,41 @@ const JKPeopleSearch = forwardRef((props, ref) => {
|
|||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (resetFilter) {
|
||||
reset();
|
||||
setResetFilter(false);
|
||||
if(resetFilter){
|
||||
reset()
|
||||
setResetFilter(false)
|
||||
}
|
||||
}, [resetFilter]);
|
||||
}, [resetFilter])
|
||||
|
||||
useEffect(() => {
|
||||
fetchGenres();
|
||||
fetchInstruments();
|
||||
//handleSubmit(onSubmit)();
|
||||
}, []);
|
||||
|
||||
const submitForm = event => {
|
||||
if(event){
|
||||
event.preventDefault();
|
||||
}
|
||||
console.log("BEFORE CLEAR");
|
||||
dispatch(clearPeople())
|
||||
event.preventDefault();
|
||||
handleSubmit(onSubmit)();
|
||||
setShow(false);
|
||||
};
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
getResults(page) {
|
||||
setPage(page)
|
||||
console.log("GET RESULTS", page);
|
||||
handleSubmit(onSubmit)();
|
||||
//submitForm()
|
||||
//setShow(false);
|
||||
}
|
||||
}));
|
||||
|
||||
const onSubmit = data => {
|
||||
console.log("Submitting......");
|
||||
let genres = [];
|
||||
let joined_within_days,
|
||||
active_within_days = '';
|
||||
|
||||
if (data.genres) {
|
||||
genres = data.genres.map(genre => genre.value);
|
||||
const onSubmit = (data) => {
|
||||
let genres = []
|
||||
let joined_within_days, active_within_days = ''
|
||||
|
||||
if(data.genres){
|
||||
genres = data.genres.map(genre => genre.value)
|
||||
}
|
||||
joined_within_days = data.joined_within_days.value;
|
||||
active_within_days = data.active_within_days.value;
|
||||
|
||||
const updatedData = { ...data, genres, joined_within_days, active_within_days };
|
||||
|
||||
|
||||
const updatedData = {...data, genres, joined_within_days, active_within_days}
|
||||
|
||||
try {
|
||||
dispatch(fetchPeople({ data: updatedData, page: page }));
|
||||
dispatch(fetchPeople({data: updatedData, page: 1}))
|
||||
} catch (error) {
|
||||
console.log('Error fetching people', error);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const lastActiveOpts = [
|
||||
|
|
@ -148,166 +132,164 @@ const JKPeopleSearch = forwardRef((props, ref) => {
|
|||
];
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={show}
|
||||
toggle={toggle}
|
||||
className="mw-100 mx-1 mr-1 ml-1 mx-md-5 mr-md-5 ml-md-5 mx-xl-10 mr-xl-10 ml-xl-10"
|
||||
data-testid="modalUpdateSearch"
|
||||
>
|
||||
<ModalHeader toggle={toggle}>Update Search</ModalHeader>
|
||||
<ModalBody>
|
||||
<div className="px-4 pb-4">
|
||||
<form>
|
||||
<div className="row justify-content-start mt-2">
|
||||
{/* first column */}
|
||||
<div className="col-12 col-md-6 mb-3 mb-md-0">
|
||||
<div className="row justify-content-start">
|
||||
<div className="col-6">
|
||||
<label className="form-label">
|
||||
Latency{' '}
|
||||
<JKTooltip title="Use these checkboxes to search for other musicians by the estimated amount of latency between you and them. Latency is the amount of time it takes for each of your computers to process audio, plus the time it takes for this digital audio to move over the Internet between you." />
|
||||
</label>
|
||||
<div className="form-check">
|
||||
<input
|
||||
{...register('latency_good')}
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
defaultChecked={!isDirty}
|
||||
onChange={e => setValue('latency_good', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">Good (less than 40ms)</label>
|
||||
|
||||
<Modal isOpen={show} toggle={toggle} className="mw-100 mx-1 mr-1 ml-1 mx-md-5 mr-md-5 ml-md-5 mx-xl-10 mr-xl-10 ml-xl-10" data-testid="modalUpdateSearch">
|
||||
<ModalHeader toggle={toggle}>Update Search</ModalHeader>
|
||||
<ModalBody>
|
||||
<div className="px-4 pb-4">
|
||||
<form>
|
||||
<div className="row justify-content-start mt-2">
|
||||
{/* first column */}
|
||||
<div className="col-12 col-md-6 mb-3 mb-md-0">
|
||||
<div className="row justify-content-start">
|
||||
<div className="col-6">
|
||||
<label className="form-label">
|
||||
Latency{' '}
|
||||
<JKTooltip title="Use these checkboxes to search for other musicians by the estimated amount of latency between you and them. Latency is the amount of time it takes for each of your computers to process audio, plus the time it takes for this digital audio to move over the Internet between you." />
|
||||
</label>
|
||||
<div className="form-check">
|
||||
<input
|
||||
{...register('latency_good')}
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
defaultChecked={!isDirty}
|
||||
onChange={e => setValue('latency_good', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">Good (less than 40ms)</label>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input
|
||||
{...register('latency_fair')}
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
defaultChecked={!isDirty}
|
||||
onChange={e => setValue('latency_fair', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">Fair (40-60ms)</label>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input
|
||||
{...register('latency_high')}
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
defaultChecked={isDirty}
|
||||
onChange={e => setValue('latency_high', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">Poor (more than 60ms)</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input
|
||||
{...register('latency_fair')}
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
defaultChecked={!isDirty}
|
||||
onChange={e => setValue('latency_fair', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">Fair (40-60ms)</label>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input
|
||||
{...register('latency_high')}
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
defaultChecked={isDirty}
|
||||
onChange={e => setValue('latency_high', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">Poor (more than 60ms)</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-6">
|
||||
<label className="form-label">
|
||||
Skill Level{' '}
|
||||
<JKTooltip title="Use these checkboxes to search for other musicians by their skill level." />
|
||||
</label>
|
||||
<div className="form-check">
|
||||
<input
|
||||
{...register('proficiency_beginner')}
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
defaultChecked={!isDirty}
|
||||
onChange={e => setValue('proficiency_beginner', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">Beginner</label>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input
|
||||
{...register('proficiency_intermediate')}
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
defaultChecked={!isDirty}
|
||||
onChange={e => setValue('proficiency_intermediate', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">Intermediate</label>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input
|
||||
{...register('proficiency_expert')}
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
defaultChecked={!isDirty}
|
||||
onChange={e => setValue('proficiency_expert', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">Expert</label>
|
||||
<div className="col-6">
|
||||
<label className="form-label">
|
||||
Skill Level <JKTooltip title="Use these checkboxes to search for other musicians by their skill level." />
|
||||
</label>
|
||||
<div className="form-check">
|
||||
<input
|
||||
{...register('proficiency_beginner')}
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
defaultChecked={!isDirty}
|
||||
onChange={e => setValue('proficiency_beginner', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">Beginner</label>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input
|
||||
{...register('proficiency_intermediate')}
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
defaultChecked={!isDirty}
|
||||
onChange={e => setValue('proficiency_intermediate', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">Intermediate</label>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input
|
||||
{...register('proficiency_expert')}
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
defaultChecked={!isDirty}
|
||||
onChange={e => setValue('proficiency_expert', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">Expert</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* second column */}
|
||||
<div className="col-12 col-md-6">
|
||||
<label className="form-label" htmlFor="instruments">
|
||||
Instruments{' '}
|
||||
<JKTooltip title="Use these checkboxes to search for other musicians who play particular instruments. If you do not select any instruments, we search for any/all instruments. If you select multiple instruments, we search for musicians who play any of these instruments." />
|
||||
</label>
|
||||
<div className="choices">
|
||||
{/* second column */}
|
||||
<div className="col-12 col-md-6">
|
||||
<label className="form-label" htmlFor="instruments">
|
||||
Instruments{' '}
|
||||
<JKTooltip title="Use these checkboxes to search for other musicians who play particular instruments. If you do not select any instruments, we search for any/all instruments. If you select multiple instruments, we search for musicians who play any of these instruments." />
|
||||
</label>
|
||||
<div className="choices">
|
||||
<Controller
|
||||
name="instruments"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select {...field} options={instruments} isMulti closeMenuOnSelect={false} id="selInstruments" />
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<label className="form-label" htmlFor="genres">
|
||||
Genres{' '}
|
||||
<JKTooltip title="Use these checkboxes to search for other musicians who enjoy playing particular musical genres/styles. If you do not select any genres, we search for any/all genres. If you select multiple genres, we search for musicians who play any of these genres." />
|
||||
</label>
|
||||
<div className="choices">
|
||||
<Controller
|
||||
name="instruments"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select {...field} options={instruments} isMulti closeMenuOnSelect={false} id="selInstruments" />
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<label className="form-label" htmlFor="genres">
|
||||
Genres{' '}
|
||||
<JKTooltip title="Use these checkboxes to search for other musicians who enjoy playing particular musical genres/styles. If you do not select any genres, we search for any/all genres. If you select multiple genres, we search for musicians who play any of these genres." />
|
||||
</label>
|
||||
<div className="choices">
|
||||
<Controller
|
||||
name="genres"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select {...field} options={genres} isMulti closeMenuOnSelect={false} id="selGenres" />
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<label className="form-label" htmlFor="lastActive">
|
||||
Last Active{' '}
|
||||
<JKTooltip title="Use this list to search for other musicians who have been active on JamKazam within a specified time period. More recent activity makes it more likely they will respond if you message or request to connect." />
|
||||
</label>
|
||||
<div className="choices">
|
||||
<Controller
|
||||
name="active_within_days"
|
||||
control={control}
|
||||
render={({ field }) => <Select {...field} options={lastActiveOpts} id="selLastActive" />}
|
||||
/>
|
||||
</div>
|
||||
<label className="form-label" htmlFor="joined">
|
||||
Joined JamKazam{' '}
|
||||
<JKTooltip title="Use this list to search for other musicians based on when they joined JamKazam. This can be useful for finding and connecting with newer users." />
|
||||
</label>
|
||||
<div className="choices">
|
||||
<Controller
|
||||
name="joined_within_days"
|
||||
control={control}
|
||||
render={({ field }) => <Select {...field} options={joinedOpts} id="selJoinedWithin" />}
|
||||
/>
|
||||
name="genres"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select {...field} options={genres} isMulti closeMenuOnSelect={false} id="selGenres" />
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<label className="form-label" htmlFor="lastActive">
|
||||
Last Active <JKTooltip title="Use this list to search for other musicians who have been active on JamKazam within a specified time period. More recent activity makes it more likely they will respond if you message or request to connect." />
|
||||
</label>
|
||||
<div className="choices">
|
||||
<Controller
|
||||
name="active_within_days"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select {...field } options={lastActiveOpts} id="selLastActive" />
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<label className="form-label" htmlFor="joined">
|
||||
Joined JamKazam <JKTooltip title="Use this list to search for other musicians based on when they joined JamKazam. This can be useful for finding and connecting with newer users." />
|
||||
</label>
|
||||
<div className="choices">
|
||||
<Controller
|
||||
name="joined_within_days"
|
||||
control={control}
|
||||
render={({ field}) => (
|
||||
<Select {...field} options={joinedOpts} id="selJoinedWithin" />
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="outline-primary" onClick={toggle}>
|
||||
Cancel
|
||||
</Button>{' '}
|
||||
<Button color="primary" onClick={submitForm} data-testid="btnSubmitSearch">
|
||||
Search
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
</form>
|
||||
</div>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="outline-primary" onClick={toggle}>
|
||||
Cancel
|
||||
</Button>{' '}
|
||||
<Button color="primary" onClick={submitForm} data-testid="btnSubmitSearch">
|
||||
Search
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
JKPeopleSearch.propTypes = {
|
||||
show: PropTypes.bool,
|
||||
setShow: PropTypes.func
|
||||
setShow: PropTypes.func,
|
||||
//setPeople: PropTypes.func
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@ const JKLatencyBadge = ({ latencyData, showAll }) => {
|
|||
setLatencyLabel(latencyData.ars_total_latency);
|
||||
|
||||
if (showAll) {
|
||||
setLatencyInfo(`${latencyData.ars_internet_latency}ms + ${latencyData.audio_latency}ms`);
|
||||
setLatencyInfo(`${Math.round(latencyData.ars_internet_latency)}ms + ${Math.round(latencyData.audio_latency)}ms`);
|
||||
} else {
|
||||
setLatencyInfo(`${latencyData.ars_total_latency}ms`);
|
||||
setLatencyInfo(`${Math.round(latencyData.ars_total_latency)}ms`);
|
||||
}
|
||||
}
|
||||
}, [latencyData]);
|
||||
|
|
|
|||
|
|
@ -1,102 +1,95 @@
|
|||
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"
|
||||
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
|
||||
import { getPeople, getPersonById, acceptFriendRequest as accept } from '../../helpers/rest';
|
||||
|
||||
const initialState = {
|
||||
people: [],
|
||||
status: 'idel',
|
||||
error: null,
|
||||
totalPages: 0,
|
||||
}
|
||||
totalPages: 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 fetchPerson = createAsyncThunk(
|
||||
'people/fetchPerson',
|
||||
'people/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)
|
||||
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);
|
||||
console.log('fetchPerson Condition', person);
|
||||
if(person && person.website){
|
||||
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(
|
||||
'people/acceptFriendRequest',
|
||||
async(options) => {
|
||||
const { userId, ...rest } = options
|
||||
const response = await accept(userId, rest)
|
||||
return response.json()
|
||||
}
|
||||
)
|
||||
export const acceptFriendRequest = createAsyncThunk('people/acceptFriendRequest', async options => {
|
||||
const { userId, ...rest } = options;
|
||||
const response = await accept(userId, rest);
|
||||
return response.json();
|
||||
});
|
||||
|
||||
export const peopleSlice = createSlice({
|
||||
name: 'people',
|
||||
initialState,
|
||||
reducers: {
|
||||
add: (state, action) => {
|
||||
state.people.push(action.payload)
|
||||
},
|
||||
resetState: () => {
|
||||
console.log("RESET STATE");
|
||||
return { ...initialState }
|
||||
state.people.push(action.payload);
|
||||
},
|
||||
resetPeople: state => {
|
||||
//state.people = []
|
||||
//state.totalPages = 0
|
||||
}
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
extraReducers: builder => {
|
||||
builder
|
||||
.addCase(fetchPeople.pending, (state, action) => {
|
||||
state.status = 'loading'
|
||||
})
|
||||
.addCase(fetchPeople.fulfilled, (state, action) => {
|
||||
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.status = 'succeeded'
|
||||
})
|
||||
.addCase(fetchPeople.rejected, (state, action) => {
|
||||
state.status = 'failed'
|
||||
state.error = action.error.message
|
||||
})
|
||||
.addCase(acceptFriendRequest.fulfilled, (state, action) => {
|
||||
.addCase(fetchPeople.pending, (state, action) => {
|
||||
state.status = 'loading';
|
||||
})
|
||||
.addCase(fetchPeople.fulfilled, (state, action) => {
|
||||
const records = new Set([...state.people, ...action.payload.musicians]);
|
||||
|
||||
})
|
||||
.addCase(fetchPerson.fulfilled, (state, action) => {
|
||||
const person = state.people.find(person => person.id === action.payload.id)
|
||||
if(person){
|
||||
const updated = {
|
||||
...person,
|
||||
...action.payload
|
||||
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.status = 'succeeded';
|
||||
})
|
||||
.addCase(fetchPeople.rejected, (state, action) => {
|
||||
state.status = 'failed';
|
||||
state.error = action.error.message;
|
||||
})
|
||||
.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);
|
||||
}
|
||||
const objIndex = state.people.findIndex((p => p.id === updated.id));
|
||||
state.people[objIndex] = updated
|
||||
}else{
|
||||
state.people.push(action.payload)
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
export const selectPersonById = (state, userId) => state.people.find((person) => person.id === userId)
|
||||
export const selectPersonById = (state, userId) => state.people.find(person => person.id === userId);
|
||||
|
||||
export const { add, resetPeople } = peopleSlice.actions;
|
||||
|
||||
export const { add, resetState } = peopleSlice.actions;
|
||||
|
||||
export default peopleSlice.reducer;
|
||||
export default peopleSlice.reducer;
|
||||
|
|
|
|||
|
|
@ -150,7 +150,6 @@ module JamRuby
|
|||
unless (instruments = query_data[KEY_INSTRUMENTS]).blank?
|
||||
instrids = self.class.instrument_ids
|
||||
instruments = instruments.select { |ii| instrids.has_key?(ii['instrument_id']) }
|
||||
#debugger
|
||||
unless instruments.blank?
|
||||
instsql = "SELECT player_id FROM musicians_instruments WHERE (("
|
||||
instsql += instruments.collect do |inst|
|
||||
|
|
|
|||
|
|
@ -150,11 +150,19 @@ module JamRuby
|
|||
rel
|
||||
end
|
||||
|
||||
def do_search(params={}, user_ids = [])
|
||||
def do_search(params={}, user_ids)
|
||||
rel = User.musicians.where('users.id <> ?', self.user.id)
|
||||
if user_ids.any?
|
||||
rel = rel.where(id: user_ids).where('users.id <> ?', self.user.id)
|
||||
|
||||
#user_ids parameter is used to track users returned from neo4j user's latency data service. #if this variable is defined means we are calling this method to fiter musicians with latency data (currently this call only comes from api_search_controller#filter)
|
||||
|
||||
if defined?(user_ids)
|
||||
if user_ids.empty?
|
||||
return User.none # no user_ids have been passed from latency service. which means no results for the latency based filter conditions. So we return an empty result
|
||||
else
|
||||
rel = rel.where(id: user_ids).where('users.id <> ?', self.user.id)
|
||||
end
|
||||
end
|
||||
|
||||
rel = Search.scope_schools_together(rel, self.user)
|
||||
rel = self._genres(rel)
|
||||
rel = self._ages(rel)
|
||||
|
|
|
|||
|
|
@ -104,26 +104,23 @@ class ApiSearchController < ApiController
|
|||
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])
|
||||
|
||||
|
||||
#begin
|
||||
|
||||
#bm = Benchmark.measure do
|
||||
@latency_data = users_latency_data(latency_good, latency_fair, latency_high)
|
||||
#end
|
||||
@latency_data = []
|
||||
begin
|
||||
if latency_good || latency_fair || latency_high
|
||||
#bm = Benchmark.measure do
|
||||
@latency_data = users_latency_data(latency_good, latency_fair, latency_high)
|
||||
#end
|
||||
end
|
||||
|
||||
# Bugsnag.notify("search_users_benchmark") do |report|
|
||||
# report.severity = "info"
|
||||
# report.add_tab(:benchmark, benchmark: bm.to_s)
|
||||
# end if Rails.env.production?
|
||||
|
||||
|
||||
|
||||
user_ids = @latency_data.map{ |l_data| l_data[:user_id] }
|
||||
Rails.logger.info "user_ids from neo4j: #{user_ids}"
|
||||
|
||||
#debugger
|
||||
|
||||
|
||||
filter_params = {
|
||||
"sort_order"=>"latency",
|
||||
"instruments"=>[],
|
||||
|
|
@ -163,24 +160,26 @@ class ApiSearchController < ApiController
|
|||
filter_params.merge!(joined_within_days: params[:joined_within_days]) unless params[:joined_within_days].blank?
|
||||
filter_params.merge!(active_within_days: params[:active_within_days]) unless params[:active_within_days].blank?
|
||||
|
||||
sobj = MusicianSearch.user_search_filter(current_user)
|
||||
@search = sobj.search_results_page(filter_params, [params[:page].to_i, 1].max, user_ids)
|
||||
#debugger
|
||||
|
||||
sobj = MusicianSearch.user_search_filter(current_user)
|
||||
@search = sobj.search_results_page(filter_params, [params[:page].to_i, 1].max, user_ids)
|
||||
|
||||
respond_with @search, responder: ApiResponder, status: 201, template: 'api_search/index'
|
||||
|
||||
# rescue => exception
|
||||
# logger.debug("Latency exception: #{exception.message}")
|
||||
# Bugsnag.notify(exception) do |report|
|
||||
# report.severity = "error"
|
||||
# report.add_tab(:latency, {
|
||||
# params: params,
|
||||
# user_id: current_user.id,
|
||||
# name: current_user.name,
|
||||
# url: filter_latency_url,
|
||||
# })
|
||||
# end
|
||||
# render json: {}, status: 500
|
||||
# end
|
||||
rescue => exception
|
||||
logger.debug("Latency exception: #{exception.message}")
|
||||
Bugsnag.notify(exception) do |report|
|
||||
report.severity = "error"
|
||||
report.add_tab(:latency, {
|
||||
params: params,
|
||||
user_id: current_user.id,
|
||||
name: current_user.name,
|
||||
url: filter_latency_url,
|
||||
})
|
||||
end
|
||||
render json: {}, status: 500
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -12,63 +12,64 @@ module LatencyHelper
|
|||
|
||||
def users_latency_data(latency_good, latency_fair, latency_high)
|
||||
latency_data = []
|
||||
#if latency_good || latency_fair || latency_high
|
||||
uri = URI(filter_latency_url)
|
||||
begin
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
http.use_ssl = true if Rails.application.config.latency_data_host.start_with?("https://")
|
||||
req = Net::HTTP::Post.new(uri)
|
||||
req["Authorization"] = "Basic #{Rails.application.config.latency_data_host_auth_code}"
|
||||
req["Content-Type"] = "application/json"
|
||||
req.body = {
|
||||
my_user_id: current_user.id,
|
||||
my_public_ip: request.remote_ip,
|
||||
my_device_id: nil,
|
||||
my_client_id: nil
|
||||
}.to_json
|
||||
|
||||
uri = URI(filter_latency_url)
|
||||
begin
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
http.use_ssl = true if Rails.application.config.latency_data_host.start_with?("https://")
|
||||
req = Net::HTTP::Post.new(uri)
|
||||
req["Authorization"] = "Basic #{Rails.application.config.latency_data_host_auth_code}"
|
||||
req["Content-Type"] = "application/json"
|
||||
req.body = {
|
||||
my_user_id: current_user.id,
|
||||
my_public_ip: request.remote_ip,
|
||||
my_device_id: nil,
|
||||
my_client_id: nil
|
||||
}.to_json
|
||||
|
||||
response = http.request(req)
|
||||
|
||||
if response.is_a?(Net::HTTPOK) || response.is_a?(Net::HTTPSuccess)
|
||||
graph_db_users = JSON.parse(response.body)["users"]
|
||||
#debugger
|
||||
if latency_good || latency_fair || latency_high
|
||||
#fiter by latency params
|
||||
graph_db_users.select! do |user|
|
||||
total_latency = user["ars"]["total_latency"].to_f
|
||||
(total_latency >= LATENCY_SCORES[:good][:min] && total_latency <= LATENCY_SCORES[:good][:max] && latency_good) ||
|
||||
(total_latency > LATENCY_SCORES[:fair][:min] && total_latency <= LATENCY_SCORES[:fair][:max] && latency_fair) ||
|
||||
(total_latency > LATENCY_SCORES[:high][:min] && latency_high)
|
||||
end
|
||||
end
|
||||
response = http.request(req)
|
||||
|
||||
if response.is_a?(Net::HTTPOK) || response.is_a?(Net::HTTPSuccess)
|
||||
graph_db_users = JSON.parse(response.body)["users"]
|
||||
|
||||
latency_data = graph_db_users.map { | user |
|
||||
{
|
||||
user_id: user["user_id"],
|
||||
audio_latency: user["audio_latency"].to_f,
|
||||
ars_total_latency: user["ars"]["total_latency"].to_f,
|
||||
ars_internet_latency: user["ars"]["internet_latency"].to_f
|
||||
}
|
||||
}.uniq
|
||||
return latency_data
|
||||
else
|
||||
logger.debug("Latency response failed: #{response}")
|
||||
Bugsnag.notify("LatencyResponseFailed") do |report|
|
||||
report.severity = "faliure"
|
||||
report.add_tab(:latency, {
|
||||
user_id: current_user.id,
|
||||
name: current_user.name,
|
||||
params: params,
|
||||
url: filter_latency_url,
|
||||
code: response.code,
|
||||
body: response.body,
|
||||
})
|
||||
end
|
||||
if latency_good || latency_fair || latency_high
|
||||
#fiter by latency params
|
||||
graph_db_users.select! do |user|
|
||||
total_latency = user["ars"]["total_latency"].to_f
|
||||
(total_latency >= LATENCY_SCORES[:good][:min] && total_latency <= LATENCY_SCORES[:good][:max] && latency_good) ||
|
||||
(total_latency > LATENCY_SCORES[:fair][:min] && total_latency <= LATENCY_SCORES[:fair][:max] && latency_fair) ||
|
||||
(total_latency > LATENCY_SCORES[:high][:min] && latency_high)
|
||||
end
|
||||
end
|
||||
|
||||
latency_data = graph_db_users.map { | user |
|
||||
{
|
||||
user_id: user["user_id"],
|
||||
audio_latency: user["audio_latency"].to_f,
|
||||
ars_total_latency: user["ars"]["total_latency"].to_f,
|
||||
ars_internet_latency: user["ars"]["internet_latency"].to_f
|
||||
}
|
||||
}.uniq
|
||||
|
||||
return latency_data
|
||||
else
|
||||
logger.debug("Latency response failed: #{response}")
|
||||
Bugsnag.notify("LatencyResponseFailed") do |report|
|
||||
report.severity = "faliure"
|
||||
report.add_tab(:latency, {
|
||||
user_id: current_user.id,
|
||||
name: current_user.name,
|
||||
params: params,
|
||||
url: filter_latency_url,
|
||||
code: response.code,
|
||||
body: response.body,
|
||||
})
|
||||
end
|
||||
rescue => exception
|
||||
raise exception
|
||||
end
|
||||
#end
|
||||
rescue => exception
|
||||
raise exception
|
||||
end
|
||||
|
||||
latency_data
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue