wip - react components related to musician listing and filtering
This commit is contained in:
parent
eb4c327eff
commit
6c88cd1215
|
|
@ -0,0 +1,79 @@
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User1",
|
||||||
|
"name": "Test User1",
|
||||||
|
"city": "Denver",
|
||||||
|
"state": "CO",
|
||||||
|
"country": "US",
|
||||||
|
"location": "Denver, CO",
|
||||||
|
"online": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"musician": true,
|
||||||
|
"gender": "M",
|
||||||
|
"birth_date": null,
|
||||||
|
"friend_count": 1,
|
||||||
|
"liker_count": 0,
|
||||||
|
"follower_count": 0,
|
||||||
|
"following_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"biography": "Biography of Test User1",
|
||||||
|
"favorite_count": 0,
|
||||||
|
"audio_latency": null,
|
||||||
|
"upcoming_session_count": 0,
|
||||||
|
"age": null,
|
||||||
|
"website": "www.testuser1.com",
|
||||||
|
"skill_level": 2,
|
||||||
|
"concert_count": 4,
|
||||||
|
"studio_session_count": 4,
|
||||||
|
"virtual_band": true,
|
||||||
|
"virtual_band_commitment": 2,
|
||||||
|
"traditional_band": true,
|
||||||
|
"traditional_band_commitment": 4,
|
||||||
|
"traditional_band_touring": true,
|
||||||
|
"paid_sessions": true,
|
||||||
|
"paid_sessions_hourly_rate": 10000,
|
||||||
|
"paid_sessions_daily_rate": 200000,
|
||||||
|
"free_sessions": true,
|
||||||
|
"cowriting": true,
|
||||||
|
"cowriting_purpose": 2,
|
||||||
|
"subscribe_email": true,
|
||||||
|
"is_a_teacher": false,
|
||||||
|
"is_a_student": false,
|
||||||
|
"online_presences": [
|
||||||
|
{ "id": "e1962204-f652-41b0-84d6-1afd7e9172be", "service_type": "soundcloud", "username": "testuser" },
|
||||||
|
{ "id": "005a7c78-db8b-4f72-a51f-d64d579c22b0", "service_type": "reverbnation", "username": "testuser" },
|
||||||
|
{ "id": "2dd22eef-03ba-4743-b65b-5a194591dc86", "service_type": "bandcamp", "username": "testuser" },
|
||||||
|
{ "id": "d6ae62b4-e1ce-4cf0-90b7-c64033533261", "service_type": "fandalism", "username": "testuser" },
|
||||||
|
{ "id": "c6e85453-0fa9-40d0-9754-8f372d6e0ed3", "service_type": "youtube", "username": "testuser" },
|
||||||
|
{ "id": "480ec1ad-ea1d-4990-9c68-d7f9c0174441", "service_type": "facebook", "username": "testuser" },
|
||||||
|
{ "id": "232b26d5-c75a-4d65-9013-a07b73c8a7ae", "service_type": "twitter", "username": "testuser" }
|
||||||
|
],
|
||||||
|
"performance_samples": [],
|
||||||
|
"genres": [
|
||||||
|
{ "genre_id": "asian", "player_type": "JamRuby::User", "genre_type": "profile" },
|
||||||
|
{ "genre_id": "classical", "player_type": "JamRuby::User", "genre_type": "profile" },
|
||||||
|
{ "genre_id": "african", "player_type": "JamRuby::User", "genre_type": "virtual_band" },
|
||||||
|
{ "genre_id": "classical", "player_type": "JamRuby::User", "genre_type": "virtual_band" },
|
||||||
|
{ "genre_id": "classical", "player_type": "JamRuby::User", "genre_type": "traditional_band" },
|
||||||
|
{ "genre_id": "blues", "player_type": "JamRuby::User", "genre_type": "free_sessions" },
|
||||||
|
{ "genre_id": "soft rock", "player_type": "JamRuby::User", "genre_type": "free_sessions" },
|
||||||
|
{ "genre_id": "celtic", "player_type": "JamRuby::User", "genre_type": "cowriting" },
|
||||||
|
{ "genre_id": "tv & movie soundtrack", "player_type": "JamRuby::User", "genre_type": "cowriting" }
|
||||||
|
],
|
||||||
|
"bands": [],
|
||||||
|
"instruments": [
|
||||||
|
{ "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1, "instrument_id": "acoustic guitar" },
|
||||||
|
{ "description": "Keyboard", "proficiency_level": 3, "priority": 8, "instrument_id": "keyboard" },
|
||||||
|
{ "description": "Ukulele", "proficiency_level": 3, "priority": 11, "instrument_id": "ukulele" },
|
||||||
|
{ "description": "Voice", "proficiency_level": 3, "priority": 13, "instrument_id": "voice" },
|
||||||
|
{ "description": "Piano", "proficiency_level": 2, "priority": 10, "instrument_id": "piano" }
|
||||||
|
],
|
||||||
|
"is_friend": true,
|
||||||
|
"is_following": false,
|
||||||
|
"is_liking": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"my_audio_latency": 5,
|
||||||
|
"internet_score": null
|
||||||
|
}
|
||||||
|
|
@ -3,32 +3,38 @@
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"first_name": "Test",
|
"first_name": "Test",
|
||||||
"last_name": "User",
|
"last_name": "User1",
|
||||||
"name": "Test User",
|
"name": "Test User1",
|
||||||
"city": "City",
|
"city": "Denver",
|
||||||
"state": "NC",
|
"state": "CO",
|
||||||
"country": "US",
|
"country": "US",
|
||||||
"online": false,
|
"online": true,
|
||||||
"musician": true,
|
"musician": true,
|
||||||
"photo_url": null,
|
"photo_url": null,
|
||||||
"biography": "",
|
"biography": "Biography of Test User1",
|
||||||
"full_score": null,
|
"full_score": null,
|
||||||
"instruments": [],
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 },
|
||||||
|
{ "instrument_id": "keyboard", "description": "Keyboard", "proficiency_level": 3, "priority": 8 },
|
||||||
|
{ "instrument_id": "ukulele", "description": "Ukulele", "proficiency_level": 3, "priority": 11 },
|
||||||
|
{ "instrument_id": "voice", "description": "Voice", "proficiency_level": 3, "priority": 13 },
|
||||||
|
{ "instrument_id": "piano", "description": "Piano", "proficiency_level": 2, "priority": 10 }
|
||||||
|
],
|
||||||
"followings": [],
|
"followings": [],
|
||||||
"is_friend": false,
|
"is_friend": true,
|
||||||
"is_following": false,
|
"is_following": false,
|
||||||
"pending_friend_request": false,
|
"pending_friend_request": false,
|
||||||
"friend_count": 0,
|
"friend_count": 1,
|
||||||
"follow_count": 0,
|
"follow_count": 0,
|
||||||
"recording_count": 0,
|
"recording_count": 0,
|
||||||
"session_count": 0,
|
"session_count": 10,
|
||||||
"audio_latency": null
|
"audio_latency": 5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "a09f9a7e-afb7-489d-870d-e13a336e0b97",
|
"id": "2",
|
||||||
"first_name": "Seth",
|
"first_name": "Test",
|
||||||
"last_name": "Call",
|
"last_name": "User2",
|
||||||
"name": "Seth Call",
|
"name": "Test User2",
|
||||||
"city": "Austin",
|
"city": "Austin",
|
||||||
"state": "TX",
|
"state": "TX",
|
||||||
"country": "US",
|
"country": "US",
|
||||||
|
|
@ -51,10 +57,10 @@
|
||||||
"audio_latency": null
|
"audio_latency": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "3dfca858-0e7c-4ad4-993a-c39421d93853",
|
"id": "3",
|
||||||
"first_name": "Peter",
|
"first_name": "Test",
|
||||||
"last_name": "Walker",
|
"last_name": "User3",
|
||||||
"name": "Peter Walker",
|
"name": "Test User3",
|
||||||
"city": "Austin",
|
"city": "Austin",
|
||||||
"state": "TX",
|
"state": "TX",
|
||||||
"country": "US",
|
"country": "US",
|
||||||
|
|
@ -77,10 +83,10 @@
|
||||||
"audio_latency": null
|
"audio_latency": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "963d5268-66b6-463a-a3ee-c97f274fc23f",
|
"id": "4",
|
||||||
"first_name": "Peter",
|
"first_name": "Test",
|
||||||
"last_name": "Walker",
|
"last_name": "User4",
|
||||||
"name": "Peter Walker",
|
"name": "Test User4",
|
||||||
"city": "Austin",
|
"city": "Austin",
|
||||||
"state": "TX",
|
"state": "TX",
|
||||||
"country": "US",
|
"country": "US",
|
||||||
|
|
@ -103,10 +109,10 @@
|
||||||
"audio_latency": null
|
"audio_latency": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "feb671a3-1821-48f0-bc14-aa26cf98bb25",
|
"id": "5",
|
||||||
"first_name": "David",
|
"first_name": "Test",
|
||||||
"last_name": "Wilson",
|
"last_name": "User5",
|
||||||
"name": "David Wilson",
|
"name": "Test User5",
|
||||||
"city": "Austin",
|
"city": "Austin",
|
||||||
"state": "TX",
|
"state": "TX",
|
||||||
"country": "US",
|
"country": "US",
|
||||||
|
|
@ -129,10 +135,379 @@
|
||||||
"audio_latency": null
|
"audio_latency": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "b1ddadd0-0263-47c4-bf91-e7767f386970",
|
"id": "6",
|
||||||
"first_name": "Oswald",
|
"first_name": "Test",
|
||||||
"last_name": "Becca",
|
"last_name": "User6",
|
||||||
"name": "Oswald Becca",
|
"name": "Test User6",
|
||||||
|
"city": "Austin",
|
||||||
|
"state": "TX",
|
||||||
|
"country": "US",
|
||||||
|
"online": false,
|
||||||
|
"musician": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"biography": "",
|
||||||
|
"full_score": null,
|
||||||
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 }
|
||||||
|
],
|
||||||
|
"followings": [],
|
||||||
|
"is_friend": false,
|
||||||
|
"is_following": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"friend_count": 0,
|
||||||
|
"follow_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"audio_latency": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "7",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User7",
|
||||||
|
"name": "Test User7",
|
||||||
|
"city": "Austin",
|
||||||
|
"state": "TX",
|
||||||
|
"country": "US",
|
||||||
|
"online": false,
|
||||||
|
"musician": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"biography": "",
|
||||||
|
"full_score": null,
|
||||||
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 }
|
||||||
|
],
|
||||||
|
"followings": [],
|
||||||
|
"is_friend": false,
|
||||||
|
"is_following": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"friend_count": 0,
|
||||||
|
"follow_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"audio_latency": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User8",
|
||||||
|
"name": "Test User8",
|
||||||
|
"city": "Austin",
|
||||||
|
"state": "TX",
|
||||||
|
"country": "US",
|
||||||
|
"online": false,
|
||||||
|
"musician": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"biography": "",
|
||||||
|
"full_score": null,
|
||||||
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 }
|
||||||
|
],
|
||||||
|
"followings": [],
|
||||||
|
"is_friend": false,
|
||||||
|
"is_following": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"friend_count": 0,
|
||||||
|
"follow_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"audio_latency": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User9",
|
||||||
|
"name": "Test User9",
|
||||||
|
"city": "Austin",
|
||||||
|
"state": "TX",
|
||||||
|
"country": "US",
|
||||||
|
"online": false,
|
||||||
|
"musician": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"biography": "",
|
||||||
|
"full_score": null,
|
||||||
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 }
|
||||||
|
],
|
||||||
|
"followings": [],
|
||||||
|
"is_friend": false,
|
||||||
|
"is_following": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"friend_count": 0,
|
||||||
|
"follow_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"audio_latency": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "10",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User10",
|
||||||
|
"name": "Test User10",
|
||||||
|
"city": "Austin",
|
||||||
|
"state": "TX",
|
||||||
|
"country": "US",
|
||||||
|
"online": false,
|
||||||
|
"musician": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"biography": "",
|
||||||
|
"full_score": null,
|
||||||
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 }
|
||||||
|
],
|
||||||
|
"followings": [],
|
||||||
|
"is_friend": false,
|
||||||
|
"is_following": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"friend_count": 0,
|
||||||
|
"follow_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"audio_latency": null
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": "11",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User11",
|
||||||
|
"name": "Test User11",
|
||||||
|
"city": "Denver",
|
||||||
|
"state": "CO",
|
||||||
|
"country": "US",
|
||||||
|
"online": true,
|
||||||
|
"musician": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"biography": "Biography of Test User1",
|
||||||
|
"full_score": null,
|
||||||
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 },
|
||||||
|
{ "instrument_id": "keyboard", "description": "Keyboard", "proficiency_level": 3, "priority": 8 },
|
||||||
|
{ "instrument_id": "ukulele", "description": "Ukulele", "proficiency_level": 3, "priority": 11 },
|
||||||
|
{ "instrument_id": "voice", "description": "Voice", "proficiency_level": 3, "priority": 13 },
|
||||||
|
{ "instrument_id": "piano", "description": "Piano", "proficiency_level": 2, "priority": 10 }
|
||||||
|
],
|
||||||
|
"followings": [],
|
||||||
|
"is_friend": true,
|
||||||
|
"is_following": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"friend_count": 1,
|
||||||
|
"follow_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 10,
|
||||||
|
"audio_latency": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "12",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User12",
|
||||||
|
"name": "Test User12",
|
||||||
|
"city": "Austin",
|
||||||
|
"state": "TX",
|
||||||
|
"country": "US",
|
||||||
|
"online": false,
|
||||||
|
"musician": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"biography": "",
|
||||||
|
"full_score": null,
|
||||||
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 }
|
||||||
|
],
|
||||||
|
"followings": [],
|
||||||
|
"is_friend": false,
|
||||||
|
"is_following": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"friend_count": 0,
|
||||||
|
"follow_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"audio_latency": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "13",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User13",
|
||||||
|
"name": "Test User13",
|
||||||
|
"city": "Austin",
|
||||||
|
"state": "TX",
|
||||||
|
"country": "US",
|
||||||
|
"online": false,
|
||||||
|
"musician": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"biography": "",
|
||||||
|
"full_score": null,
|
||||||
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 }
|
||||||
|
],
|
||||||
|
"followings": [],
|
||||||
|
"is_friend": false,
|
||||||
|
"is_following": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"friend_count": 0,
|
||||||
|
"follow_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"audio_latency": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "14",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User14",
|
||||||
|
"name": "Test User14",
|
||||||
|
"city": "Austin",
|
||||||
|
"state": "TX",
|
||||||
|
"country": "US",
|
||||||
|
"online": false,
|
||||||
|
"musician": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"biography": "",
|
||||||
|
"full_score": null,
|
||||||
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 }
|
||||||
|
],
|
||||||
|
"followings": [],
|
||||||
|
"is_friend": false,
|
||||||
|
"is_following": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"friend_count": 0,
|
||||||
|
"follow_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"audio_latency": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "15",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User15",
|
||||||
|
"name": "Test User15",
|
||||||
|
"city": "Austin",
|
||||||
|
"state": "TX",
|
||||||
|
"country": "US",
|
||||||
|
"online": false,
|
||||||
|
"musician": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"biography": "",
|
||||||
|
"full_score": null,
|
||||||
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 }
|
||||||
|
],
|
||||||
|
"followings": [],
|
||||||
|
"is_friend": false,
|
||||||
|
"is_following": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"friend_count": 0,
|
||||||
|
"follow_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"audio_latency": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "16",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User16",
|
||||||
|
"name": "Test User16",
|
||||||
|
"city": "Austin",
|
||||||
|
"state": "TX",
|
||||||
|
"country": "US",
|
||||||
|
"online": false,
|
||||||
|
"musician": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"biography": "",
|
||||||
|
"full_score": null,
|
||||||
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 }
|
||||||
|
],
|
||||||
|
"followings": [],
|
||||||
|
"is_friend": false,
|
||||||
|
"is_following": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"friend_count": 0,
|
||||||
|
"follow_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"audio_latency": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "17",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User17",
|
||||||
|
"name": "Test User17",
|
||||||
|
"city": "Austin",
|
||||||
|
"state": "TX",
|
||||||
|
"country": "US",
|
||||||
|
"online": false,
|
||||||
|
"musician": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"biography": "",
|
||||||
|
"full_score": null,
|
||||||
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 }
|
||||||
|
],
|
||||||
|
"followings": [],
|
||||||
|
"is_friend": false,
|
||||||
|
"is_following": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"friend_count": 0,
|
||||||
|
"follow_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"audio_latency": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "18",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User18",
|
||||||
|
"name": "Test User18",
|
||||||
|
"city": "Austin",
|
||||||
|
"state": "TX",
|
||||||
|
"country": "US",
|
||||||
|
"online": false,
|
||||||
|
"musician": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"biography": "",
|
||||||
|
"full_score": null,
|
||||||
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 }
|
||||||
|
],
|
||||||
|
"followings": [],
|
||||||
|
"is_friend": false,
|
||||||
|
"is_following": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"friend_count": 0,
|
||||||
|
"follow_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"audio_latency": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "19",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User19",
|
||||||
|
"name": "Test User19",
|
||||||
|
"city": "Austin",
|
||||||
|
"state": "TX",
|
||||||
|
"country": "US",
|
||||||
|
"online": false,
|
||||||
|
"musician": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"biography": "",
|
||||||
|
"full_score": null,
|
||||||
|
"instruments": [
|
||||||
|
{ "instrument_id": "acoustic guitar", "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1 }
|
||||||
|
],
|
||||||
|
"followings": [],
|
||||||
|
"is_friend": false,
|
||||||
|
"is_following": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"friend_count": 0,
|
||||||
|
"follow_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"audio_latency": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "20",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User20",
|
||||||
|
"name": "Test User20",
|
||||||
"city": "Austin",
|
"city": "Austin",
|
||||||
"state": "TX",
|
"state": "TX",
|
||||||
"country": "US",
|
"country": "US",
|
||||||
|
|
@ -155,7 +530,7 @@
|
||||||
"audio_latency": null
|
"audio_latency": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"page_count": 1,
|
"page_count": 2,
|
||||||
"my_audio_latency": 5,
|
"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\"}}",
|
"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\"}}",
|
||||||
"description": "Current Search: Sort = Latency to Me",
|
"description": "Current Search: Sort = Latency to Me",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"first_name": "Test",
|
||||||
|
"last_name": "User1",
|
||||||
|
"name": "Test User1",
|
||||||
|
"city": "Denver",
|
||||||
|
"state": "CO",
|
||||||
|
"country": "US",
|
||||||
|
"location": "Denver, CO",
|
||||||
|
"online": true,
|
||||||
|
"photo_url": null,
|
||||||
|
"musician": true,
|
||||||
|
"gender": "M",
|
||||||
|
"birth_date": null,
|
||||||
|
"friend_count": 1,
|
||||||
|
"liker_count": 0,
|
||||||
|
"follower_count": 0,
|
||||||
|
"following_count": 0,
|
||||||
|
"recording_count": 0,
|
||||||
|
"session_count": 0,
|
||||||
|
"biography": "Biography of Test User1",
|
||||||
|
"favorite_count": 0,
|
||||||
|
"audio_latency": null,
|
||||||
|
"upcoming_session_count": 0,
|
||||||
|
"age": null,
|
||||||
|
"website": "www.testuser1.com",
|
||||||
|
"skill_level": 2,
|
||||||
|
"concert_count": 4,
|
||||||
|
"studio_session_count": 4,
|
||||||
|
"virtual_band": true,
|
||||||
|
"virtual_band_commitment": 2,
|
||||||
|
"traditional_band": true,
|
||||||
|
"traditional_band_commitment": 4,
|
||||||
|
"traditional_band_touring": true,
|
||||||
|
"paid_sessions": true,
|
||||||
|
"paid_sessions_hourly_rate": 10000,
|
||||||
|
"paid_sessions_daily_rate": 200000,
|
||||||
|
"free_sessions": true,
|
||||||
|
"cowriting": true,
|
||||||
|
"cowriting_purpose": 2,
|
||||||
|
"subscribe_email": true,
|
||||||
|
"is_a_teacher": false,
|
||||||
|
"is_a_student": false,
|
||||||
|
"online_presences": [
|
||||||
|
{ "id": "e1962204-f652-41b0-84d6-1afd7e9172be", "service_type": "soundcloud", "username": "testuser" },
|
||||||
|
{ "id": "005a7c78-db8b-4f72-a51f-d64d579c22b0", "service_type": "reverbnation", "username": "testuser" },
|
||||||
|
{ "id": "2dd22eef-03ba-4743-b65b-5a194591dc86", "service_type": "bandcamp", "username": "testuser" },
|
||||||
|
{ "id": "d6ae62b4-e1ce-4cf0-90b7-c64033533261", "service_type": "fandalism", "username": "testuser" },
|
||||||
|
{ "id": "c6e85453-0fa9-40d0-9754-8f372d6e0ed3", "service_type": "youtube", "username": "testuser" },
|
||||||
|
{ "id": "480ec1ad-ea1d-4990-9c68-d7f9c0174441", "service_type": "facebook", "username": "testuser" },
|
||||||
|
{ "id": "232b26d5-c75a-4d65-9013-a07b73c8a7ae", "service_type": "twitter", "username": "testuser" }
|
||||||
|
],
|
||||||
|
"performance_samples": [],
|
||||||
|
"genres": [
|
||||||
|
{ "genre_id": "asian", "player_type": "JamRuby::User", "genre_type": "profile" },
|
||||||
|
{ "genre_id": "classical", "player_type": "JamRuby::User", "genre_type": "profile" },
|
||||||
|
{ "genre_id": "african", "player_type": "JamRuby::User", "genre_type": "virtual_band" },
|
||||||
|
{ "genre_id": "classical", "player_type": "JamRuby::User", "genre_type": "virtual_band" },
|
||||||
|
{ "genre_id": "classical", "player_type": "JamRuby::User", "genre_type": "traditional_band" },
|
||||||
|
{ "genre_id": "blues", "player_type": "JamRuby::User", "genre_type": "free_sessions" },
|
||||||
|
{ "genre_id": "soft rock", "player_type": "JamRuby::User", "genre_type": "free_sessions" },
|
||||||
|
{ "genre_id": "celtic", "player_type": "JamRuby::User", "genre_type": "cowriting" },
|
||||||
|
{ "genre_id": "tv & movie soundtrack", "player_type": "JamRuby::User", "genre_type": "cowriting" }
|
||||||
|
],
|
||||||
|
"bands": [],
|
||||||
|
"instruments": [
|
||||||
|
{ "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1, "instrument_id": "acoustic guitar" },
|
||||||
|
{ "description": "Keyboard", "proficiency_level": 3, "priority": 8, "instrument_id": "keyboard" },
|
||||||
|
{ "description": "Ukulele", "proficiency_level": 3, "priority": 11, "instrument_id": "ukulele" },
|
||||||
|
{ "description": "Voice", "proficiency_level": 3, "priority": 13, "instrument_id": "voice" },
|
||||||
|
{ "description": "Piano", "proficiency_level": 2, "priority": 10, "instrument_id": "piano" }
|
||||||
|
],
|
||||||
|
"is_friend": false,
|
||||||
|
"is_following": false,
|
||||||
|
"is_liking": false,
|
||||||
|
"pending_friend_request": false,
|
||||||
|
"my_audio_latency": 5,
|
||||||
|
"internet_score": null
|
||||||
|
}
|
||||||
|
|
@ -1,35 +1,107 @@
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import { iteratee } from "lodash"
|
describe('Friends page', () => {
|
||||||
|
|
||||||
describe("Friends Index page", () => {
|
|
||||||
describe('For unauthenticated user', () => {
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.stubUnauthenticate()
|
cy.stubAuthenticate();
|
||||||
cy.visit('/friends')
|
cy.intercept('POST', /\S+\/filter/, { fixture: 'people' });
|
||||||
})
|
});
|
||||||
|
|
||||||
it("should not list musicians", () => {
|
describe('friends list', () => {
|
||||||
cy.contains("Find New Friends").should('exist')
|
|
||||||
cy.contains("Update Search").should('exist')
|
|
||||||
cy.contains("Reset Filters").should('exist')
|
|
||||||
cy.get('[data-testid=peopleListTable]').should('not.exist')
|
|
||||||
})
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("For authenticated user", () => {
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.stubAuthenticate()
|
cy.visit('/friends');
|
||||||
cy.intercept('GET', '/filter', { fixture: 'people' })
|
});
|
||||||
cy.visit('/friends')
|
|
||||||
|
it('lists musicians', () => {
|
||||||
|
cy.contains('Find New Friends').should('exist');
|
||||||
|
cy.contains('Update Search').should('exist');
|
||||||
|
cy.contains('Reset Filters').should('exist');
|
||||||
|
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||||
|
.should('have.length', 20)
|
||||||
|
.first()
|
||||||
|
.contains('Test User1');
|
||||||
|
});
|
||||||
|
|
||||||
|
//TODO: paginate
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('details side panel', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
|
||||||
|
cy.visit('/friends');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows profile side panel', () => {
|
||||||
|
//open side panel by clicking name
|
||||||
|
cy.contains('Test User1').click();
|
||||||
|
cy.get('[data-testid=profileSidePanel]')
|
||||||
|
.should('be.visible')
|
||||||
|
.contains('Biography of Test User1');
|
||||||
|
closeMoreDetailsSidePanel()
|
||||||
|
|
||||||
|
//open side panel by clicking more button
|
||||||
|
cy.get('[data-testid=peopleListTable] > tbody tr').first().find('[data-testid=btnMore]').click()
|
||||||
|
cy.get('[data-testid=profileSidePanel]')
|
||||||
|
.should('be.visible')
|
||||||
|
.contains('Biography of Test User1');
|
||||||
|
closeMoreDetailsSidePanel()
|
||||||
|
|
||||||
|
//open side panel by clicking more link
|
||||||
|
cy.get('[data-testid=peopleListTable] > tbody tr').first().find('[data-testid=linkMore]').click()
|
||||||
|
cy.get('[data-testid=profileSidePanel]')
|
||||||
|
.should('be.visible')
|
||||||
|
.contains('Biography of Test User1');
|
||||||
|
closeMoreDetailsSidePanel()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('making friendship', () => {
|
||||||
|
|
||||||
|
it('add friend', () => {
|
||||||
|
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
|
||||||
|
cy.intercept('POST', /\S+\/friend_requests/, { statusCode: 201, body: { ok: true } });
|
||||||
|
|
||||||
|
cy.visit('/friends');
|
||||||
|
cy.contains('Test User1').click();
|
||||||
|
|
||||||
|
cy.get('[data-testid=profileSidePanel]')
|
||||||
|
.find('[data-testid=connect]')
|
||||||
|
.should('not.be.disabled')
|
||||||
|
.click();
|
||||||
|
cy.get('[data-testid=profileSidePanel]')
|
||||||
|
.find('[data-testid=connect]')
|
||||||
|
.should('be.disabled');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('remove friend', () => {
|
||||||
|
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'friend' });
|
||||||
|
cy.intercept('DELETE', /\S+\/friends\S+/, { statusCode: 204, body: { ok: true } });
|
||||||
|
|
||||||
|
cy.visit('/friends');
|
||||||
|
cy.contains('Test User1').click();
|
||||||
|
|
||||||
|
cy.get('[data-testid=profileSidePanel]')
|
||||||
|
.find('[data-testid=disconnect]')
|
||||||
|
.should('exist')
|
||||||
|
.should('not.be.disabled')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.get('[data-testid=profileSidePanel]')
|
||||||
|
.find('[data-testid=disconnect]')
|
||||||
|
.should('not.exist');
|
||||||
|
|
||||||
|
cy.get('[data-testid=profileSidePanel]')
|
||||||
|
.find('[data-testid=connect]')
|
||||||
|
.should('be.exist')
|
||||||
|
.should('not.be.disabled')
|
||||||
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should list musicians", () => {
|
describe('send message', () => {
|
||||||
cy.get('[data-testid=peopleListTable]').should('exist')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
function closeMoreDetailsSidePanel(){
|
||||||
|
cy.get('[data-testid=profileSidePanel] .modal-header button.close').click()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,9 @@ describe("Top Navigation", () => {
|
||||||
it("shows user dropdown", () => {
|
it("shows user dropdown", () => {
|
||||||
showSubscribeToUpdates()
|
showSubscribeToUpdates()
|
||||||
cy.get('[data-testid=navbarTopProfileDropdown]').should('exist')
|
cy.get('[data-testid=navbarTopProfileDropdown]').should('exist')
|
||||||
cy.contains("Peter Pan")
|
cy.contains("Peter Pan").should('exist')
|
||||||
cy.contains("My Profile")
|
cy.contains("My Profile").should('exist')
|
||||||
cy.contains("Sign out")
|
cy.contains("Sign out").should('exist')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,3 +18,6 @@ import './commands'
|
||||||
|
|
||||||
// Alternatively you can use CommonJS syntax:
|
// Alternatively you can use CommonJS syntax:
|
||||||
// require('./commands')
|
// require('./commands')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5906,6 +5906,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
|
||||||
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
|
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
|
||||||
},
|
},
|
||||||
|
"dom7": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom7/-/dom7-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ssr-window": "^3.0.0-alpha.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"domain-browser": {
|
"domain-browser": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
|
||||||
|
|
@ -16813,6 +16822,12 @@
|
||||||
"tweetnacl": "~0.14.0"
|
"tweetnacl": "~0.14.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ssr-window": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"ssri": {
|
"ssri": {
|
||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.1.tgz",
|
||||||
|
|
@ -17293,6 +17308,16 @@
|
||||||
"util.promisify": "~1.0.0"
|
"util.promisify": "~1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"swiper": {
|
||||||
|
"version": "6.8.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/swiper/-/swiper-6.8.2.tgz",
|
||||||
|
"integrity": "sha512-VwBZ40NQ8vDzIZO9wApJTf4bDu/o3sgURMQ6fvJVSc9T63NoJV0KLC/mjkrl9GepGbmlCQNLR2tL0Kk/r8NSdw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"dom7": "^3.0.0",
|
||||||
|
"ssr-window": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"symbol-observable": {
|
"symbol-observable": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@
|
||||||
"gulp-rtlcss": "^1.4.1",
|
"gulp-rtlcss": "^1.4.1",
|
||||||
"gulp-sass": "^4.1.0",
|
"gulp-sass": "^4.1.0",
|
||||||
"gulp-sourcemaps": "^2.6.5",
|
"gulp-sourcemaps": "^2.6.5",
|
||||||
"prettier": "1.17.1"
|
"prettier": "1.17.1",
|
||||||
|
"swiper": "^6.8.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -11,7 +11,6 @@
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Poppins:100,200,300,400,500,600,700,800,900&display=swap"
|
href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Poppins:100,200,300,400,500,600,700,800,900&display=swap"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<title>JamKazam</title>
|
<title>JamKazam</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 22 KiB |
|
|
@ -3,3 +3,10 @@
|
||||||
// user-variables.scss
|
// user-variables.scss
|
||||||
//
|
//
|
||||||
// Place your own variable overrides here, these will override any Bootstrap and theme variables.
|
// Place your own variable overrides here, these will override any Bootstrap and theme variables.
|
||||||
|
|
||||||
|
$jk-navigation-link-color: #2c7be5 !default;
|
||||||
|
$jk-navigation-text-color: #313336 !default;
|
||||||
|
|
||||||
|
$dropdown-link-color: rgba($jk-navigation-link-color, 1) !default;
|
||||||
|
$link-color: rgba($jk-navigation-link-color, 1) !default;
|
||||||
|
$navbar-light-color: rgba($jk-navigation-link-color, 1) !default;
|
||||||
|
|
@ -4,4 +4,6 @@
|
||||||
//
|
//
|
||||||
// Place your own theme CSS or SCSS rules below this line, these rules will override any Bootstrap and theme variables.
|
// Place your own theme CSS or SCSS rules below this line, these rules will override any Bootstrap and theme variables.
|
||||||
|
|
||||||
@import './custom/user.css';
|
@import './custom/nav';
|
||||||
|
@import './custom/user';
|
||||||
|
@import './custom/form';
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
|
||||||
|
.form-check {
|
||||||
|
display: block;
|
||||||
|
min-height: 1.5rem;
|
||||||
|
padding-left: 1.5em;
|
||||||
|
margin-bottom: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Choices */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
.choices {
|
||||||
|
position:relative;
|
||||||
|
margin-bottom:24px;
|
||||||
|
font-size:16px
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
.navbar-light{
|
||||||
|
.navbar-text {
|
||||||
|
color: $jk-navigation-text-color;
|
||||||
|
a {
|
||||||
|
color: $jk-navigation-text-color;
|
||||||
|
|
||||||
|
@include hover-focus() {
|
||||||
|
color: $navbar-light-active-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
--jk-good: #198754;
|
--jk-good: #198754;
|
||||||
--jk-fair: #e0a500;
|
--jk-fair: #e0a500;
|
||||||
--jk-high: #990000;
|
--jk-high: #990000;
|
||||||
|
--jk-unknown: #8a8787;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-active .nav-link-text{
|
.nav-active .nav-link-text{
|
||||||
|
|
@ -31,7 +32,13 @@
|
||||||
|
|
||||||
.latency-high {
|
.latency-high {
|
||||||
background-color: var(--jk-high);
|
background-color: var(--jk-high);
|
||||||
color: white;
|
color: rgb(247, 239, 239);
|
||||||
|
min-width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.latency-unknown {
|
||||||
|
background-color: var(--jk-unknown);
|
||||||
|
color: rgb(253, 251, 251);
|
||||||
min-width: 50px;
|
min-width: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,3 +71,35 @@
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 2000;
|
z-index: 2000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.swiper-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swiper-slide {
|
||||||
|
// text-align: center;
|
||||||
|
// font-size: 18px;
|
||||||
|
// background: #fff;
|
||||||
|
|
||||||
|
// /* Center slide text vertically */
|
||||||
|
// display: -webkit-box;
|
||||||
|
// display: -ms-flexbox;
|
||||||
|
// display: -webkit-flex;
|
||||||
|
// display: flex;
|
||||||
|
// -webkit-box-pack: center;
|
||||||
|
// -ms-flex-pack: center;
|
||||||
|
// -webkit-justify-content: center;
|
||||||
|
// justify-content: center;
|
||||||
|
// -webkit-box-align: center;
|
||||||
|
// -ms-flex-align: center;
|
||||||
|
// -webkit-align-items: center;
|
||||||
|
// align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swiper-slide img {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: initial;
|
margin-right: initial;
|
||||||
max-width: 350px;
|
max-width: 600px;
|
||||||
}
|
}
|
||||||
// .modal-content {
|
// .modal-content {
|
||||||
// border-radius: 0;
|
// border-radius: 0;
|
||||||
|
|
@ -27,7 +27,8 @@
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
padding: 0.5rem 1.25rem;
|
padding: 0.5rem 1.25rem;
|
||||||
background-image: linear-gradient(-45deg, #4695ff, #1970e2);
|
border-bottom: solid 1px #ddd;
|
||||||
|
//background-image: linear-gradient(-45deg, #4695ff, #1970e2);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
&:before,
|
&:before,
|
||||||
&:after {
|
&:after {
|
||||||
|
|
@ -36,7 +37,7 @@
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
height: 12.5rem;
|
height: 12.5rem;
|
||||||
width: 12.5rem;
|
width: 12.5rem;
|
||||||
background-image: linear-gradient(45deg, #318aff, #247cef);
|
//background-image: linear-gradient(45deg, #318aff, #247cef);
|
||||||
}
|
}
|
||||||
&:after {
|
&:after {
|
||||||
left: 5.125rem;
|
left: 5.125rem;
|
||||||
|
|
@ -51,7 +52,7 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
color: white;
|
color: #333;
|
||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
padding-top: 0.75rem;
|
padding-top: 0.75rem;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ const JKCurrentUserAvatar = () => {
|
||||||
const { currentUser } = useAuth();
|
const { currentUser } = useAuth();
|
||||||
|
|
||||||
if(currentUser && currentUser.photo_url) {
|
if(currentUser && currentUser.photo_url) {
|
||||||
return ( <img className="avatar avatar-xl rounded-circle" src={currentUser.photo_url} /> );
|
return ( <img className="avatar avatar-xl rounded-circle mr-1" src={currentUser.photo_url} /> );
|
||||||
}else {
|
}else {
|
||||||
return ( <img className="avatar avatar-xl rounded-circle" src={avatar} /> );
|
return ( <img className="avatar avatar-xl rounded-circle mr-1" src={avatar} /> );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,40 +6,43 @@ import { Link } from 'react-router-dom';
|
||||||
import JKCurrentUserAvatar from './JKCurrentUserAvatar'
|
import JKCurrentUserAvatar from './JKCurrentUserAvatar'
|
||||||
|
|
||||||
const JKNavbarTopCurrentUser = () => {
|
const JKNavbarTopCurrentUser = () => {
|
||||||
const { currentUser, setCurrentUser } = useAuth();
|
const { currentUser } = useAuth();
|
||||||
const [dropdownOpen, setDropdownOpen] = useState(false);
|
const [dropdownOpen, setDropdownOpen] = useState(false);
|
||||||
|
|
||||||
const toggle = () => setDropdownOpen(prevState => !prevState);
|
const toggle = () => setDropdownOpen(prevState => !prevState);
|
||||||
|
|
||||||
const fetchCurrentUser = () => {
|
// const fetchCurrentUser = () => {
|
||||||
getCurrentUser()
|
// getCurrentUser()
|
||||||
.then(resp => {
|
// .then(resp => {
|
||||||
if (resp.ok) {
|
// if (resp.ok) {
|
||||||
return resp.json();
|
// return resp.json();
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
.then(data => {
|
// .then(data => {
|
||||||
console.log('CURRENT_USER', data);
|
// console.log('CURRENT_USER', data);
|
||||||
setCurrentUser(data);
|
// setCurrentUser(data);
|
||||||
})
|
// })
|
||||||
.catch(error => console.log(error));
|
// .catch(error => console.log(error));
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleLogout = () => {};
|
const handleLogout = () => {};
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
fetchCurrentUser();
|
// fetchCurrentUser();
|
||||||
}, []);
|
// }, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{currentUser &&
|
{currentUser &&
|
||||||
<Dropdown isOpen={dropdownOpen} toggle={toggle} data-testid="navbarTopProfileDropdown">
|
<Dropdown isOpen={dropdownOpen} toggle={toggle} data-testid="navbarTopProfileDropdown">
|
||||||
<DropdownToggle nav={true} caret>
|
<DropdownToggle nav={true}>
|
||||||
<JKCurrentUserAvatar />
|
<JKCurrentUserAvatar />
|
||||||
|
<span className="d-none d-lg-inline navbar-text">
|
||||||
{currentUser.name}
|
{currentUser.name}
|
||||||
|
</span>
|
||||||
|
|
||||||
</DropdownToggle>
|
</DropdownToggle>
|
||||||
<DropdownMenu>
|
<DropdownMenu right={true}>
|
||||||
<DropdownItem tag={Link} to="/pages/settings">
|
<DropdownItem tag={Link} to="/pages/settings">
|
||||||
My Profile
|
My Profile
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ const Logo = ({ at, width, className, ...rest }) => {
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
|
||||||
{
|
{
|
||||||
'align-items-center py-3': at === 'navbar-vertical',
|
'align-items-center p-2': at === 'navbar-vertical',
|
||||||
'align-items-center': at === 'navbar-top',
|
'align-items-center': at === 'navbar-top',
|
||||||
'flex-center font-weight-extra-bold fs-5 mb-4': at === 'auth'
|
'flex-center font-weight-extra-bold fs-5 mb-4': at === 'auth'
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ import { Collapse, Navbar, NavItem, Nav } from 'reactstrap';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import AppContext from '../../context/Context';
|
import AppContext from '../../context/Context';
|
||||||
import Logo from './Logo';
|
import Logo from './Logo';
|
||||||
import SearchBox from './SearchBox';
|
//import SearchBox from './SearchBox';
|
||||||
import TopNavRightSideNavItem from './TopNavRightSideNavItem';
|
import TopNavRightSideNavItem from './TopNavRightSideNavItem';
|
||||||
import NavbarTopDropDownMenus from './NavbarTopDropDownMenus';
|
//import NavbarTopDropDownMenus from './NavbarTopDropDownMenus';
|
||||||
import { navbarBreakPoint, topNavbarBreakpoint } from '../../config';
|
import { navbarBreakPoint, topNavbarBreakpoint } from '../../config';
|
||||||
import autoCompleteInitialItem from '../../data/autocomplete/autocomplete';
|
//import autoCompleteInitialItem from '../../data/autocomplete/autocomplete';
|
||||||
|
|
||||||
const NavbarTop = () => {
|
const NavbarTop = () => {
|
||||||
const {
|
const {
|
||||||
|
|
@ -26,7 +26,7 @@ const NavbarTop = () => {
|
||||||
return (
|
return (
|
||||||
<Navbar
|
<Navbar
|
||||||
light
|
light
|
||||||
className="navbar-glass fs--1 font-weight-semi-bold row navbar-top sticky-kit"
|
className="navbar-glass fs--1 font-weight-semi-bold row navbar-top sticky-kit mb-3 d-flex"
|
||||||
expand={isTopNav && topNavbarBreakpoint}
|
expand={isTopNav && topNavbarBreakpoint}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ const NavbarVertical = ({ navbarStyle }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Nav navbar vertical>
|
<Nav navbar vertical className="mt-3">
|
||||||
<NavbarVerticalMenu routes={routes} />
|
<NavbarVerticalMenu routes={routes} />
|
||||||
</Nav>
|
</Nav>
|
||||||
<div className="settings px-3 px-xl-0">
|
<div className="settings px-3 px-xl-0">
|
||||||
|
|
@ -101,7 +101,7 @@ const NavbarVertical = ({ navbarStyle }) => {
|
||||||
</Nav>
|
</Nav>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="navbar-vertical-divider">
|
{/* <div className="navbar-vertical-divider">
|
||||||
<hr className="navbar-vertical-hr my-2" />
|
<hr className="navbar-vertical-hr my-2" />
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -114,7 +114,7 @@ const NavbarVertical = ({ navbarStyle }) => {
|
||||||
className="my-3 btn-purchase"
|
className="my-3 btn-purchase"
|
||||||
>
|
>
|
||||||
Purchase
|
Purchase
|
||||||
</Button>
|
</Button> */}
|
||||||
</div>
|
</div>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</Navbar>
|
</Navbar>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ const NavbarVerticalMenuItem = ({ route }) => (
|
||||||
<FontAwesomeIcon icon={route.icon} />
|
<FontAwesomeIcon icon={route.icon} />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<span className="nav-link-text">{route.name}</span>
|
<span className="nav-link-text pl-1">{route.name}</span>
|
||||||
{!!route.badge && (
|
{!!route.badge && (
|
||||||
<Badge color={route.badge.color || 'soft-success'} pill className="ml-2">
|
<Badge color={route.badge.color || 'soft-success'} pill className="ml-2">
|
||||||
{route.badge.text}
|
{route.badge.text}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
//import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Link, useHistory } from 'react-router-dom';
|
import { Link, useHistory } from 'react-router-dom';
|
||||||
import { DropdownItem, DropdownMenu, DropdownToggle, Dropdown } from 'reactstrap';
|
import { DropdownItem, DropdownMenu, DropdownToggle, Dropdown } from 'reactstrap';
|
||||||
import team3 from '../../assets/img/team/3.jpg';
|
|
||||||
import Avatar from '../common/Avatar';
|
|
||||||
import { useAuth } from '../../context/AuthContext';
|
import { useAuth } from '../../context/AuthContext';
|
||||||
|
|
||||||
const ProfileDropdown = () => {
|
const ProfileDropdown = () => {
|
||||||
|
|
@ -19,7 +17,7 @@ const ProfileDropdown = () => {
|
||||||
// removeCookie("remember_token", {
|
// removeCookie("remember_token", {
|
||||||
// domain: ".jamkazam.local"
|
// domain: ".jamkazam.local"
|
||||||
// });
|
// });
|
||||||
history.push('/authentication/basic/logout');
|
// history.push('/authentication/basic/logout');
|
||||||
console.log("signout...");
|
console.log("signout...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { Nav, NavItem, NavLink, UncontrolledTooltip } from 'reactstrap';
|
import { Navbar, Nav, NavItem, NavLink, NavbarText } from 'reactstrap';
|
||||||
// import ProfileDropdown from './ProfileDropdown';
|
// import ProfileDropdown from './ProfileDropdown';
|
||||||
// import NotificationDropdown from './NotificationDropdown';
|
// import NotificationDropdown from './NotificationDropdown';
|
||||||
// import SettingsAnimatedIcon from './SettingsAnimatedIcon';
|
// import SettingsAnimatedIcon from './SettingsAnimatedIcon';
|
||||||
|
|
@ -14,32 +14,17 @@ import JKNavbarTopProfile from './JKNavbarTopProfile';
|
||||||
const TopNavRightSideNavItem = () => {
|
const TopNavRightSideNavItem = () => {
|
||||||
const { isTopNav, isCombo } = useContext(AppContext);
|
const { isTopNav, isCombo } = useContext(AppContext);
|
||||||
return (
|
return (
|
||||||
<Nav navbar className="navbar-nav-icons ml-auto flex-row align-items-center">
|
<Navbar expand="md" className="ml-auto">
|
||||||
{/* <NavItem>
|
<Nav className="align-items-center" navbar>
|
||||||
<SettingsAnimatedIcon />
|
<NavbarText className="d-none d-md-inline">Keep JamKazam Improving:</NavbarText>
|
||||||
</NavItem> */}
|
<NavItem className="d-none d-md-inline mr-5">
|
||||||
{/* {(isCombo || isTopNav) && (
|
<NavLink>Subscribe</NavLink>
|
||||||
<NavItem className={classNames(`p-2 px-lg-0 cursor-pointer`, { [`d-${navbarBreakPoint}-none`]: isCombo })}>
|
|
||||||
<NavLink tag={Link} to="/changelog" id="changelog">
|
|
||||||
<FontAwesomeIcon icon="code-branch" transform="right-6 grow-4" />
|
|
||||||
</NavLink>
|
|
||||||
<UncontrolledTooltip autohide={false} placement="left" target="changelog">
|
|
||||||
Changelog
|
|
||||||
</UncontrolledTooltip>
|
|
||||||
</NavItem>
|
</NavItem>
|
||||||
)} */}
|
<NavItem>
|
||||||
{/* <CartNotification /> */}
|
|
||||||
{/* <NotificationDropdown /> */}
|
|
||||||
|
|
||||||
<NavItem className="me-4 d-none d-md-inline">
|
|
||||||
<div className="navbar-text d-inline">Keep JamKazam Improving:</div>
|
|
||||||
<NavLink className="text-green d-inline navbar-text nav-link">Subscribe</NavLink>
|
|
||||||
</NavItem>
|
|
||||||
|
|
||||||
<NavItem className="nav-item me-2">
|
|
||||||
<JKNavbarTopProfile />
|
<JKNavbarTopProfile />
|
||||||
</NavItem>
|
</NavItem>
|
||||||
</Nav>
|
</Nav>
|
||||||
|
</Navbar>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, {useState, useEffect} from 'react';
|
import React, { useState, useEffect, Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Alert, Card, CardBody, Col, Row, Button } from 'reactstrap';
|
import { Alert, Card, CardBody, Col, Row, Button, Pagination, PaginationItem, PaginationLink, Form } from 'reactstrap';
|
||||||
import Loader from '../common/Loader';
|
import Loader from '../common/Loader';
|
||||||
import FalconCardHeader from '../common/FalconCardHeader';
|
import FalconCardHeader from '../common/FalconCardHeader';
|
||||||
import { isIterableArray } from '../../helpers/utils';
|
import { isIterableArray } from '../../helpers/utils';
|
||||||
|
|
@ -8,9 +8,10 @@ import { isIterableArray } from '../../helpers/utils';
|
||||||
// import rawPeople from '../../data/people/people';
|
// import rawPeople from '../../data/people/people';
|
||||||
// import peopleCategories from '../../data/people/peopleCategories';
|
// import peopleCategories from '../../data/people/peopleCategories';
|
||||||
// import apiFetch from '../../helpers/apiFetch';
|
// import apiFetch from '../../helpers/apiFetch';
|
||||||
import JKPeopleSearch from "./JKPeopleSearch";
|
import JKPeopleSearch from './JKPeopleSearch';
|
||||||
import JKPeopleList from './JKPeopleList';
|
import JKPeopleList from './JKPeopleList';
|
||||||
import { getPeople } from "../../helpers/rest";
|
import { getMusicians, getPeople } from '../../helpers/rest';
|
||||||
|
import JKPeopleSwiper from './JKPeopleSwiper';
|
||||||
|
|
||||||
const JKPeople = ({ className }) => {
|
const JKPeople = ({ className }) => {
|
||||||
//const { loading, data: people, setData: setPeople } = useFakeFetch(rawPeople);
|
//const { loading, data: people, setData: setPeople } = useFakeFetch(rawPeople);
|
||||||
|
|
@ -18,63 +19,95 @@ const JKPeople = ({ className }) => {
|
||||||
const [people, setPeople] = useState([]);
|
const [people, setPeople] = useState([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [showSearch, setShowSearch] = useState(false);
|
const [showSearch, setShowSearch] = useState(false);
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
const [totalPages, setTotalPages] = useState(0);
|
||||||
|
|
||||||
const fetchPeople = React.useCallback( () => {
|
const fetchPeople = React.useCallback(page => {
|
||||||
getPeople()
|
//getMusicians(page)
|
||||||
|
console.log("PAGE", page);
|
||||||
|
getPeople({ page: page })
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
//TODO: handle failure
|
//TODO: handle failure
|
||||||
console.log(response);
|
//console.log(response);
|
||||||
throw new Error('Network response was not ok');
|
throw new Error('Network response was not ok');
|
||||||
}
|
}
|
||||||
return response.json();
|
return response.json();
|
||||||
})
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
console.log('people received', data);
|
console.log('PEOPLE', data.musicians);
|
||||||
setPeople(data.musicians);
|
//const users = new Set([...people, ...data.musicians]);
|
||||||
|
//console.log("new users", users);
|
||||||
|
//setPeople(Array.from(users));
|
||||||
|
|
||||||
|
setPeople(prev => Array.from(new Set([...prev, ...data.musicians])))
|
||||||
|
|
||||||
|
setTotalPages(data.page_count);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
//TODO: handle error
|
//TODO: handle error
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}).finally(() => {
|
})
|
||||||
setLoading(false)
|
.finally(() => {
|
||||||
|
setLoading(false);
|
||||||
});
|
});
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchPeople();
|
fetchPeople(page);
|
||||||
}, [fetchPeople])
|
}, [page]);
|
||||||
|
|
||||||
const searchPeople = ({ target }) => {
|
const goNextPage = () => {
|
||||||
const keyword = target.value.toLowerCase();
|
if (page < totalPages) {
|
||||||
const filteredResult = people.filter(
|
setPage(val => ++val);
|
||||||
person => person.name.toLowerCase().includes(keyword) || person.institution.toLowerCase().includes(keyword)
|
}
|
||||||
);
|
|
||||||
|
|
||||||
setPeople(keyword.length ? filteredResult : people);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const goPrevPage = () => {
|
||||||
|
if (page > 1) {
|
||||||
|
setPage(prev => --prev);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// const searchPeople = ({ target }) => {
|
||||||
|
// const keyword = target.value.toLowerCase();
|
||||||
|
// const filteredResult = people.filter(
|
||||||
|
// person => person.name.toLowerCase().includes(keyword) || person.institution.toLowerCase().includes(keyword)
|
||||||
|
// );
|
||||||
|
|
||||||
|
// setPeople(keyword.length ? filteredResult : people);
|
||||||
|
// };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<FalconCardHeader title="Find New Friends">
|
|
||||||
|
|
||||||
<div className="col-12 col-sm-auto">
|
|
||||||
<Button color="primary" className="me-2 fs--1" onClick={() => setShowSearch(!showSearch)}>Update Search</Button>
|
|
||||||
<Button outline disabled color="secondary" className="fs--1">Reset Filters</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</FalconCardHeader>
|
|
||||||
|
|
||||||
<JKPeopleSearch show={showSearch} setShow={setShowSearch} setPeople={setPeople} />
|
<JKPeopleSearch show={showSearch} setShow={setShowSearch} setPeople={setPeople} />
|
||||||
|
<FalconCardHeader title="Find New Friends" 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)}>
|
||||||
|
Update Search
|
||||||
|
</Button>
|
||||||
|
<Button outline disabled color="secondary" className="fs--1">
|
||||||
|
Reset Filters
|
||||||
|
</Button>
|
||||||
|
</Form>
|
||||||
|
</FalconCardHeader>
|
||||||
|
|
||||||
<CardBody className="pt-0">
|
<CardBody className="pt-0">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Loader />
|
<Loader />
|
||||||
) : isIterableArray(people) ? (
|
) : isIterableArray(people) ? (
|
||||||
//Start Find Friends table hidden on small screens
|
//Start Find Friends table hidden on small screens
|
||||||
|
<Fragment>
|
||||||
|
<Row className="mb-3 justify-content-between d-none d-md-block">
|
||||||
|
<div className="table-responsive-xl px-2">
|
||||||
|
<JKPeopleList people={people} goNextPage={goNextPage} page={page} totalPages={totalPages} />
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
|
||||||
<JKPeopleList people={people} />
|
<Row className="swiper-container d-block d-md-none">
|
||||||
|
<JKPeopleSwiper people={people} goNextPage={goNextPage} />
|
||||||
|
</Row>
|
||||||
|
</Fragment>
|
||||||
) : (
|
) : (
|
||||||
<Row className="p-card">
|
<Row className="p-card">
|
||||||
<Col>
|
<Col>
|
||||||
|
|
@ -85,8 +118,9 @@ const JKPeople = ({ className }) => {
|
||||||
</Row>
|
</Row>
|
||||||
)}
|
)}
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>);
|
</Card>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
||||||
JKPeople.propTypes = {
|
JKPeople.propTypes = {
|
||||||
className: PropTypes.string
|
className: PropTypes.string
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,47 @@
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import { Table } from 'reactstrap';
|
import { Table, Row, Col, Button } from 'reactstrap';
|
||||||
import JKPerson from './JKPerson';
|
import JKPerson from './JKPerson';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
const JKPeopleList = ({people}) => {
|
const JKPeopleList = ({ people, goNextPage, page, totalPages }) => {
|
||||||
return (
|
return (
|
||||||
<Table className="table-bordered table-striped fs--1" data-testid="peopleListTable">
|
<>
|
||||||
|
<Table striped bordered className="fs--1" data-testid="peopleListTable">
|
||||||
<thead className="bg-200 text-900">
|
<thead className="bg-200 text-900">
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">Name</th>
|
<th scope="col">Name</th>
|
||||||
<th scope="col" style={{ minWidth: 250 }}>About</th>
|
<th scope="col" style={{ minWidth: 250 }}>
|
||||||
|
About
|
||||||
|
</th>
|
||||||
<th scope="col">Instruments</th>
|
<th scope="col">Instruments</th>
|
||||||
<th scope="col">Genres</th>
|
|
||||||
<th scope="col">Action</th>
|
<th scope="col">Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="list">
|
<tbody className="list">
|
||||||
{people.map((person, index) => (
|
{people.map((person, index) => (
|
||||||
<tr className="align-middle" key={person.id}>
|
<tr className="align-middle" key={person.id}>
|
||||||
<JKPerson {...person} />
|
<JKPerson person={person} viewMode="list" />
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</Table>
|
</Table>
|
||||||
|
|
||||||
|
<Row>
|
||||||
|
<Col>
|
||||||
|
{page < totalPages && (
|
||||||
|
<a className="ml-2 fw-semi-bold" href="#!" onClick={goNextPage}>
|
||||||
|
More...
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
JKPeopleList.propTypes = {
|
JKPeopleList.propTypes = {
|
||||||
people: PropTypes.arrayOf(
|
people: PropTypes.arrayOf(PropTypes.instanceOf(Object))
|
||||||
PropTypes.instanceOf(Object)
|
};
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default JKPeopleList;
|
export default JKPeopleList;
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef, Fragment } from 'react';
|
||||||
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
|
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
|
||||||
import Select from 'react-select';
|
import Select from 'react-select';
|
||||||
import JKTooltip from '../common/JKTooltip';
|
import JKTooltip from '../common/JKTooltip';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { getGenres, getInstruments, postPeopleSearch } from '../../helpers/rest';
|
import { getGenres, getInstruments, getPeople } from '../../helpers/rest';
|
||||||
import { useForm, Controller } from 'react-hook-form';
|
import { useForm, Controller } from 'react-hook-form';
|
||||||
|
|
||||||
const JKPeopleSearch = props => {
|
const JKPeopleSearch = props => {
|
||||||
|
|
@ -54,7 +54,7 @@ const JKPeopleSearch = props => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
console.log(data);
|
//console.log(data);
|
||||||
setGenres(
|
setGenres(
|
||||||
data.map(genre => {
|
data.map(genre => {
|
||||||
return {
|
return {
|
||||||
|
|
@ -88,7 +88,7 @@ const JKPeopleSearch = props => {
|
||||||
}
|
}
|
||||||
const updatedData = {...data, genres}
|
const updatedData = {...data, genres}
|
||||||
console.log('submitting...', updatedData);
|
console.log('submitting...', updatedData);
|
||||||
await postPeopleSearch(updatedData)
|
await getPeople(updatedData)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if(!response.ok){
|
if(!response.ok){
|
||||||
//TODO: handle failure
|
//TODO: handle failure
|
||||||
|
|
@ -121,8 +121,8 @@ const JKPeopleSearch = props => {
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<Fragment>
|
||||||
<Modal isOpen={show} toggle={toggle} size="xl">
|
<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">
|
||||||
<ModalHeader toggle={toggle}>Update Search</ModalHeader>
|
<ModalHeader toggle={toggle}>Update Search</ModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<div className="px-4 pb-4">
|
<div className="px-4 pb-4">
|
||||||
|
|
@ -212,7 +212,7 @@ const JKPeopleSearch = props => {
|
||||||
Instruments{' '}
|
Instruments{' '}
|
||||||
<JKTooltip title="Select one or more instruments to filter for. If this field is blank, all instruments will be searched for." />
|
<JKTooltip title="Select one or more instruments to filter for. If this field is blank, all instruments will be searched for." />
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div className="choices">
|
||||||
<Controller
|
<Controller
|
||||||
name="instruments"
|
name="instruments"
|
||||||
control={control}
|
control={control}
|
||||||
|
|
@ -225,7 +225,7 @@ const JKPeopleSearch = props => {
|
||||||
Genres{' '}
|
Genres{' '}
|
||||||
<JKTooltip title="Select one or more genres to filter for. If this field is blank, all genres will be included." />
|
<JKTooltip title="Select one or more genres to filter for. If this field is blank, all genres will be included." />
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div className="choices">
|
||||||
<Controller
|
<Controller
|
||||||
name="genres"
|
name="genres"
|
||||||
control={control}
|
control={control}
|
||||||
|
|
@ -237,7 +237,7 @@ const JKPeopleSearch = props => {
|
||||||
<label className="form-label" htmlFor="lastActive">
|
<label className="form-label" htmlFor="lastActive">
|
||||||
Last Active <JKTooltip title="Select onefor when the user was last active on JamKazam." />
|
Last Active <JKTooltip title="Select onefor when the user was last active on JamKazam." />
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div className="choices">
|
||||||
<Controller
|
<Controller
|
||||||
name="last_active"
|
name="last_active"
|
||||||
control={control}
|
control={control}
|
||||||
|
|
@ -249,7 +249,7 @@ const JKPeopleSearch = props => {
|
||||||
<label className="form-label" htmlFor="joined">
|
<label className="form-label" htmlFor="joined">
|
||||||
Joined JamKazam <JKTooltip title="Select onefor when the user joined JamKazam." />
|
Joined JamKazam <JKTooltip title="Select onefor when the user joined JamKazam." />
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div className="choices">
|
||||||
<Controller
|
<Controller
|
||||||
name="joined"
|
name="joined"
|
||||||
control={control}
|
control={control}
|
||||||
|
|
@ -264,7 +264,7 @@ const JKPeopleSearch = props => {
|
||||||
</div>
|
</div>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button color="secondary" onClick={toggle}>
|
<Button color="outline-primary" onClick={toggle}>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>{' '}
|
</Button>{' '}
|
||||||
<Button color="primary" onClick={submitForm}>
|
<Button color="primary" onClick={submitForm}>
|
||||||
|
|
@ -272,7 +272,7 @@ const JKPeopleSearch = props => {
|
||||||
</Button>
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</Modal>
|
</Modal>
|
||||||
</div>
|
</Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
// import Swiper core and required modules
|
||||||
|
import SwiperCore, { Navigation, Pagination, Scrollbar, A11y } from 'swiper';
|
||||||
|
|
||||||
|
// Import Swiper React components
|
||||||
|
import { Swiper, SwiperSlide } from 'swiper/react';
|
||||||
|
|
||||||
|
// Import Swiper styles
|
||||||
|
import 'swiper/swiper.scss';
|
||||||
|
import 'swiper/components/navigation/navigation.scss';
|
||||||
|
import 'swiper/components/pagination/pagination.scss';
|
||||||
|
import 'swiper/components/scrollbar/scrollbar.scss';
|
||||||
|
|
||||||
|
import { Card, CardBody, CardHeader } from 'reactstrap';
|
||||||
|
|
||||||
|
import JKPerson from './JKPerson';
|
||||||
|
import JKProfileAvatar from '../profile/JKProfileAvatar';
|
||||||
|
|
||||||
|
SwiperCore.use([Navigation, Pagination, Scrollbar, A11y]);
|
||||||
|
|
||||||
|
const JKPeopleSwiper = ({ people, goNextPage }) => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Swiper
|
||||||
|
spaceBetween={0}
|
||||||
|
slidesPerView={1}
|
||||||
|
onSlideChange={() => console.log('slide change')}
|
||||||
|
onSlideNextTransitionEnd={swiper => {
|
||||||
|
if(swiper.isEnd){
|
||||||
|
goNextPage()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
pagination={{
|
||||||
|
clickable: true,
|
||||||
|
type: 'custom'
|
||||||
|
}}
|
||||||
|
navigation={{
|
||||||
|
nextEl: '.swiper-button-next',
|
||||||
|
prevEl: '.swiper-button-prev'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{people.map((person, index) => (
|
||||||
|
<SwiperSlide key={person.id}>
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="bg-200">
|
||||||
|
<div className="avatar avatar-xl d-inline-block me-2 mr-2">
|
||||||
|
<JKProfileAvatar url={person.photo_url} size="xl"/>
|
||||||
|
</div>
|
||||||
|
<h5 className="d-inline-block align-top mt-1">{person.name}</h5>
|
||||||
|
</CardHeader>
|
||||||
|
<CardBody>
|
||||||
|
<JKPerson person={person} viewMode="swipe" />
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
</SwiperSlide>
|
||||||
|
))}
|
||||||
|
</Swiper>
|
||||||
|
<div className="py-4 px-6 bg-white border-top w-100 fixed-bottom">
|
||||||
|
<div className="swiper-pagination" />
|
||||||
|
<div className="swiper-button-prev" />
|
||||||
|
<div className="swiper-button-next" />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
JKPeopleSwiper.propTypes = {
|
||||||
|
people: PropTypes.arrayOf(PropTypes.instanceOf(Object))
|
||||||
|
};
|
||||||
|
|
||||||
|
export default JKPeopleSwiper;
|
||||||
|
|
@ -1,56 +1,60 @@
|
||||||
import React, { Fragment, useState } from 'react';
|
import React, { Fragment, useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { Row, Col } from 'reactstrap';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import avatar from '../../assets/img/team/avatar.png';
|
import avatar from '../../assets/img/team/avatar.png';
|
||||||
import JKProfileSidePanel from '../profile/JKProfileSidePanel';
|
import JKProfileSidePanel from '../profile/JKProfileSidePanel';
|
||||||
import JKProfileAvatar from '../profile/JKProfileAvatar';
|
import JKProfileAvatar from '../profile/JKProfileAvatar';
|
||||||
import JKProfileInstrumentsList from '../profile/JKProfileInstrumentsList';
|
import JKProfileInstrumentsList from '../profile/JKProfileInstrumentsList';
|
||||||
import {getUserProfile} from '../../helpers/rest';
|
import { getPersonById } from '../../helpers/rest';
|
||||||
|
import JKConnectButton from '../profile/JKConnectButton';
|
||||||
|
import JKMessageButton from '../profile/JKMessageButton';
|
||||||
|
import JKLatencyBadge from '../profile/JKLatencyBadge';
|
||||||
|
import { useAuth } from '../../context/AuthContext';
|
||||||
|
|
||||||
const JKPerson = ({ id, name, biography, photo_url, instruments }) => {
|
const JKPerson = props => {
|
||||||
|
const { id, name, biography, photo_url, instruments, latency_data } = props.person;
|
||||||
|
const viewMode = props.viewMode;
|
||||||
|
const { currentUser } = useAuth();
|
||||||
|
|
||||||
const [showSidePanel, setShowSidePanel] = useState(false)
|
const [showSidePanel, setShowSidePanel] = useState(false);
|
||||||
const [user, setUser] = useState(null);
|
const [user, setUser] = useState(null);
|
||||||
|
|
||||||
const fetchPerson = () => {
|
const fetchPerson = async () => {
|
||||||
console.log("fetchPerson called");
|
//console.log("fetchPerson called");
|
||||||
getUserProfile(id)
|
await getPersonById(id)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
return response.json()
|
return response.json();
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(json => {
|
.then(json => {
|
||||||
console.log("USER", json);
|
console.log('USER', json);
|
||||||
setUser(json)
|
setUser(json);
|
||||||
})
|
})
|
||||||
.catch(error => console.log(error))
|
.catch(error => console.log(error));
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
const toggleMoreDetails = () => {
|
const toggleMoreDetails = () => {
|
||||||
setShowSidePanel(prev => !prev)
|
fetchPerson();
|
||||||
if(!user){
|
setShowSidePanel(prev => !prev);
|
||||||
fetchPerson()
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<>
|
||||||
|
{viewMode === 'list' ? (
|
||||||
|
<>
|
||||||
<td className="text-nowrap">
|
<td className="text-nowrap">
|
||||||
<a onClick={toggleMoreDetails} className="d-flex align-items-center mb-1 fs-0">
|
<a onClick={toggleMoreDetails} className="d-flex align-items-center mb-1 fs-0">
|
||||||
<div className="avatar avatar-xl">
|
<div className="avatar avatar-xl">
|
||||||
<JKProfileAvatar url={photo_url} />
|
<JKProfileAvatar url={photo_url} />
|
||||||
</div>
|
</div>
|
||||||
<div className="ms-2">
|
<div className="ml-2 ms-2">
|
||||||
<strong>{name}</strong>
|
<strong>{name}</strong>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div>
|
<div>
|
||||||
<strong>Latency To Me:</strong> 24ms <span className="badge latency-good">GOOD</span>
|
<strong>Latency To Me:</strong>
|
||||||
|
<JKLatencyBadge latencyData={latency_data} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Last Active:</strong> 1 hour
|
<strong>Last Active:</strong> 1 hour
|
||||||
|
|
@ -59,53 +63,72 @@ const JKPerson = ({ id, name, biography, photo_url, instruments }) => {
|
||||||
<td>
|
<td>
|
||||||
{biography}
|
{biography}
|
||||||
{biography.length > 0 && (
|
{biography.length > 0 && (
|
||||||
<a onClick={toggleMoreDetails}>
|
<a data-testid="linkMore" onClick={toggleMoreDetails}>
|
||||||
{' '} more »
|
{' '} more »
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td><JKProfileInstrumentsList instruments={instruments} /></td>
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<JKProfileInstrumentsList instruments={instruments} />
|
|
||||||
</td>
|
|
||||||
<td className="text-nowrap">
|
<td className="text-nowrap">
|
||||||
<a
|
<JKConnectButton
|
||||||
href="#"
|
currentUser={currentUser}
|
||||||
className="btn fs--1 btn-primary px-2 py-1 mr-1"
|
user={props.person}
|
||||||
data-bs-toggle="tooltip"
|
addContent={<FontAwesomeIcon icon="plus" transform="shrink-4 down-1" className="mr-1" />}
|
||||||
data-bs-placement="top"
|
removeContent={<FontAwesomeIcon icon="minus" transform="shrink-4 down-1" className="mr-1" />}
|
||||||
title="Connect with This Friend"
|
cssClasses="fs--1 px-2 py-1 mr-1"
|
||||||
>
|
/>
|
||||||
<FontAwesomeIcon icon="plus" transform="shrink-4 down-1" className="mr-1" />
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a
|
<JKMessageButton currentUser={currentUser} user={props.person} cssClasses="fs--1 px-2 py-1 mr-1">
|
||||||
href="#"
|
|
||||||
className="btn btn-primary fs--1 px-2 py-1 mr-1"
|
|
||||||
data-bs-toggle="tooltip"
|
|
||||||
data-bs-placement="top"
|
|
||||||
title="Send a Message"
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon="comments" transform="shrink-4 down-1" className="mr-1" />
|
<FontAwesomeIcon icon="comments" transform="shrink-4 down-1" className="mr-1" />
|
||||||
</a>
|
</JKMessageButton>
|
||||||
|
|
||||||
<a onClick={toggleMoreDetails}>
|
<a onClick={toggleMoreDetails} data-testid="btnMore">
|
||||||
<span className="btn btn-primary fs--1 px-2 py-1" data-bs-toggle="tooltip" title="View Profile">
|
<span className="btn btn-primary fs--1 px-2 py-1" data-bs-toggle="tooltip" title="View Profile">
|
||||||
<FontAwesomeIcon icon="user" transform="shrink-4 down-1" className="mr-1" />
|
<FontAwesomeIcon icon="user" transform="shrink-4 down-1" className="mr-1" />
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<strong>Latency To Me:</strong> <JKLatencyBadge latencyData={latency_data} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong>Last Active:</strong> 1 hour
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5>Instruments</h5>
|
||||||
|
<JKProfileInstrumentsList instruments={instruments} />
|
||||||
|
|
||||||
|
<JKConnectButton
|
||||||
|
currentUser={currentUser}
|
||||||
|
user={props.person}
|
||||||
|
addContent={<FontAwesomeIcon icon="plus" transform="shrink-4 down-1" className="mr-1" />}
|
||||||
|
removeContent={<FontAwesomeIcon icon="minus" transform="shrink-4 down-1" className="mr-1" />}
|
||||||
|
cssClasses="fs--1 px-2 py-1 mr-1"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<JKMessageButton currentUser={currentUser} user={props.person} cssClasses="fs--1 px-2 py-1 mr-1">
|
||||||
|
<FontAwesomeIcon icon="comments" transform="shrink-4 down-1" className="mr-1" />
|
||||||
|
</JKMessageButton>
|
||||||
|
|
||||||
|
<a onClick={toggleMoreDetails} data-testid="btnMore">
|
||||||
|
<span className="btn btn-primary fs--1 px-2 py-1" data-bs-toggle="tooltip" title="View Profile">
|
||||||
|
<FontAwesomeIcon icon="user" transform="shrink-4 down-1" className="mr-1" />
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<JKProfileSidePanel user={user} show={showSidePanel} setShow={setShowSidePanel} />
|
<JKProfileSidePanel user={user} show={showSidePanel} setShow={setShowSidePanel} />
|
||||||
</Fragment>
|
</>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
JKPerson.propTypes = {
|
JKPerson.propTypes = {
|
||||||
id: PropTypes.string.isRequired,
|
person: PropTypes.object.isRequired,
|
||||||
name: PropTypes.string.isRequired,
|
viewMode: PropTypes.string
|
||||||
biography: PropTypes.string.isRequired,
|
|
||||||
photo_url: PropTypes.string,
|
|
||||||
//instruments: PropTypes.arrayOf(PropTypes.string)
|
//instruments: PropTypes.arrayOf(PropTypes.string)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
import React, {useEffect, useState} from 'react';
|
||||||
|
import {addFriend as connect, removeFriend as disconnect} from '../../helpers/rest';
|
||||||
|
|
||||||
|
const JKConnectButton = (props) => {
|
||||||
|
const { user, currentUser, addContent, removeContent, cssClasses } = props
|
||||||
|
const [isFriend, setIsFriend] = useState(false)
|
||||||
|
const [pendingFriendRequest, setPendingFriendRequest] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsFriend(user.is_friend);
|
||||||
|
setPendingFriendRequest(user.pending_friend_request)
|
||||||
|
}, [user])
|
||||||
|
|
||||||
|
const addFriend = () => {
|
||||||
|
connect(currentUser.id, user.id)
|
||||||
|
.then(resp => {
|
||||||
|
if(resp.ok && resp.status === 201){
|
||||||
|
setPendingFriendRequest(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => console.log(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeFriend = () => {
|
||||||
|
disconnect(currentUser.id, user.id)
|
||||||
|
.then(resp => {
|
||||||
|
if(resp.ok){
|
||||||
|
setIsFriend(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => console.log(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
const buttonTitle = () => {
|
||||||
|
let title;
|
||||||
|
if (pendingFriendRequest) {
|
||||||
|
title = 'You have sent a friend request to this user';
|
||||||
|
} else if (!isFriend) {
|
||||||
|
title = 'Send friend request';
|
||||||
|
} else if (isFriend) {
|
||||||
|
title = 'Unfriend this person';
|
||||||
|
}
|
||||||
|
return title;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{ !isFriend ? (
|
||||||
|
<button className={`btn btn-primary ${cssClasses}`} data-testid="connect" disabled={pendingFriendRequest} onClick={addFriend} title={buttonTitle()}>
|
||||||
|
{addContent}
|
||||||
|
</button>)
|
||||||
|
: (
|
||||||
|
<button className={`btn btn-primary ${cssClasses}`} data-testid="disconnect" onClick={removeFriend} title={buttonTitle()}>
|
||||||
|
{removeContent}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default JKConnectButton;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
const JKLatencyBadge = ({ latencyData, showAll }) => {
|
||||||
|
let label = 'UNKNOWN';
|
||||||
|
let latency = '';
|
||||||
|
if (latencyData) {
|
||||||
|
label = latencyData.label;
|
||||||
|
if (showAll) {
|
||||||
|
latency = `${latencyData.ars_internet_latency}ms + ${latencyData.audio_latency}ms`;
|
||||||
|
} else {
|
||||||
|
latency = `${latencyData.ars_total_latency}ms`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{latency} <span className={`badge latency-${label.toLowerCase()}`}>{label}</span>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
JKLatencyBadge.propTypes = {
|
||||||
|
latencyData: PropTypes.object,
|
||||||
|
showAll: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
|
JKLatencyBadge.defaultProps = {
|
||||||
|
showAll: false
|
||||||
|
};
|
||||||
|
|
||||||
|
export default JKLatencyBadge;
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import JKMessageModal from './JKMessageModal';
|
||||||
|
|
||||||
|
const JKMessageButton = props => {
|
||||||
|
const { currentUser, user, cssClasses, children } = props;
|
||||||
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
const [isFriend, setIsFriend] = useState(false);
|
||||||
|
const [pendingFriendRequest, setPendingFriendRequest] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsFriend(user.is_friend);
|
||||||
|
setPendingFriendRequest(user.pending_friend_request);
|
||||||
|
}, [user]);
|
||||||
|
|
||||||
|
const buttonTitle = () => {
|
||||||
|
return isFriend ? 'Send friend request' : 'You can message this user once you are friends.'
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<JKMessageModal show={showModal} setShow={setShowModal} user={user} currentUser={currentUser} />
|
||||||
|
<button
|
||||||
|
onClick={() => setShowModal(!showModal)}
|
||||||
|
className={`btn btn-primary ${cssClasses}`}
|
||||||
|
title={buttonTitle()}
|
||||||
|
data-testid="message"
|
||||||
|
disabled={!isFriend}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default JKMessageButton;
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Modal, ModalHeader, ModalBody, Row, Col, Button, ModalFooter } from 'reactstrap';
|
||||||
|
import { Scrollbar } from 'react-scrollbars-custom';
|
||||||
|
import JKProfileAvatar from './JKProfileAvatar';
|
||||||
|
import { getTextMessages, createTextMessage } from '../../helpers/rest';
|
||||||
|
|
||||||
|
const JKMessageModal = props => {
|
||||||
|
const { show, setShow, user } = props;
|
||||||
|
const [offset, setOffset] = useState(0);
|
||||||
|
const [messages, setMessages] = useState([]);
|
||||||
|
const [newMessage, setNewMessage] = useState("");
|
||||||
|
const toggle = () => setShow(!show);
|
||||||
|
const LIMIT = 20;
|
||||||
|
|
||||||
|
const fetchMessages = async () => {
|
||||||
|
await getTextMessages({
|
||||||
|
target_user_id: user.id,
|
||||||
|
offset: offset,
|
||||||
|
limit: LIMIT
|
||||||
|
})
|
||||||
|
.then(resp => {
|
||||||
|
if (resp.ok) {
|
||||||
|
return resp.json();
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(json => {
|
||||||
|
console.log(json);
|
||||||
|
setMessages(json);
|
||||||
|
})
|
||||||
|
.catch(error => console.log(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendMessage = () => {
|
||||||
|
const params = { message: newMessage, target_user_id: user.id }
|
||||||
|
console.log("Sending new message", params);
|
||||||
|
createTextMessage(params)
|
||||||
|
.then(resp => console.log(resp))
|
||||||
|
.catch(error => console.log(error))
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (show) {
|
||||||
|
console.log('JKMessageModal User', user.id);
|
||||||
|
fetchMessages();
|
||||||
|
}
|
||||||
|
}, [show]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Modal isOpen={show} toggle={toggle}>
|
||||||
|
<ModalHeader toggle={toggle}>Conversation with {user.name}</ModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
<Scrollbar style={{ width: '100%', height: 400 }}>
|
||||||
|
{messages.map((message, index) => (
|
||||||
|
<div className="d-flex mb-2 mr-1" key={message.id}>
|
||||||
|
<div className="avatar avatar-2xl d-inline-block me-2 mr-2">
|
||||||
|
<JKProfileAvatar url={user.photo_url} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="d-inline-block ml-2 ms-2 mb-0">
|
||||||
|
<p className="mb-0">{message.message}</p>
|
||||||
|
<time className="notification-time">{message.created_at}</time>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Scrollbar>
|
||||||
|
<Row>
|
||||||
|
<Col>
|
||||||
|
<textarea style={{ width: '100%' }} value={newMessage} onChange={(e) => setNewMessage(e.target.value) } />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</ModalBody>
|
||||||
|
|
||||||
|
<ModalFooter>
|
||||||
|
<Button onClick={toggle}>Close</Button>
|
||||||
|
<Button color="primary" onClick={sendMessage}>Send</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default JKMessageModal;
|
||||||
|
|
@ -1,15 +1,27 @@
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import avatar from "../../assets/img/team/avatar.png";
|
import PropTypes from 'prop-types';
|
||||||
|
import defaultAvatarUrl from '../../assets/img/team/avatar.png';
|
||||||
const JKProfileAvatar = ({url}) => {
|
import Avatar from '../common/Avatar';
|
||||||
|
|
||||||
|
|
||||||
|
const JKProfileAvatar = ({ url, size }) => {
|
||||||
|
const avatarUrl = () => {
|
||||||
if (url) {
|
if (url) {
|
||||||
return ( <img className="avatar avatar-xl rounded-circle" src={url} /> );
|
return url;
|
||||||
} else {
|
} else {
|
||||||
return ( <img className="avatar avatar-xl rounded-circle" src={avatar} /> );
|
return defaultAvatarUrl;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
return <Avatar src={avatarUrl()} size={size} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
JKProfileAvatar.propTypes = {
|
||||||
|
url: PropTypes.string,
|
||||||
|
size: PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
JKProfileAvatar.defaultProps = {
|
||||||
|
size: 'l'
|
||||||
|
};
|
||||||
|
|
||||||
export default JKProfileAvatar;
|
export default JKProfileAvatar;
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { useContext, useEffect } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Modal, ModalBody, ModalHeader } from 'reactstrap';
|
import { Modal, ModalBody, ModalHeader } from 'reactstrap';
|
||||||
import ScrollBarCustom from '../common/ScrollBarCustom';
|
import ScrollBarCustom from '../common/ScrollBarCustom';
|
||||||
|
|
@ -11,27 +11,31 @@ import JKProfileOnlinePresence from './JKProfileOnlinePresence';
|
||||||
import JKProfileInterests from './JKProfileInterests';
|
import JKProfileInterests from './JKProfileInterests';
|
||||||
import JKProfileGenres from './JKProfileGenres';
|
import JKProfileGenres from './JKProfileGenres';
|
||||||
import JKProfilePerformanceSamples from './JKProfilePerformanceSamples';
|
import JKProfilePerformanceSamples from './JKProfilePerformanceSamples';
|
||||||
|
import { useAuth } from '../../context/AuthContext';
|
||||||
|
import JKConnectButton from './JKConnectButton';
|
||||||
|
import JKLatencyBadge from './JKLatencyBadge';
|
||||||
|
|
||||||
const JKProfileSidePanel = props => {
|
const JKProfileSidePanel = props => {
|
||||||
const { show, setShow, user } = props;
|
const { show, setShow, user } = props;
|
||||||
|
const {currentUser} = useAuth()
|
||||||
const toggle = () => setShow(!show);
|
const toggle = () => setShow(!show);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen={show}
|
isOpen={show}
|
||||||
toggle={toggle}
|
toggle={toggle}
|
||||||
modalClassName="overflow-hidden modal-fixed-right modal-theme"
|
modalClassName="overflow-hidden modal-profile modal-fixed-right w-100 modal-theme"
|
||||||
className="modal-dialog-vertical"
|
className="modal-dialog-vertical"
|
||||||
contentClassName="vh-100 border-0"
|
contentClassName="vh-100 border-0"
|
||||||
|
data-testid="profileSidePanel"
|
||||||
>
|
>
|
||||||
<ModalHeader tag="div" toggle={toggle} className="modal-header-settings">
|
<ModalHeader tag="div" toggle={toggle} className="modal-header-settings">
|
||||||
{user && (
|
{user && (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="avatar avatar-2xl d-inline-block me-2">
|
<div className="avatar avatar-2xl d-inline-block me-2 mr-2">
|
||||||
<JKProfileAvatar url={user.photo_url} />
|
<JKProfileAvatar url={user.photo_url} size="2xl" />
|
||||||
</div>
|
</div>
|
||||||
<h4 className="d-inline-block align-middle mt-1">{user.name}</h4>
|
<h4 className="d-inline-block align-middle mt-n3 pt-0">{user.name}</h4>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
|
@ -43,12 +47,11 @@ const JKProfileSidePanel = props => {
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ModalBody>
|
<ModalBody className="pb-5">
|
||||||
{user && (
|
{user && (
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
<strong>Latency to Me:</strong> 18ms Internet + 8ms Audio{' '}
|
<strong>Latency to Me:</strong> <JKLatencyBadge latencyData={user.latencyData} showAll={true} />
|
||||||
<span className="badge latency-good">GOOD</span>
|
|
||||||
<br />
|
<br />
|
||||||
<strong>Location:</strong> {`${user.city}, ${user.country}`}
|
<strong>Location:</strong> {`${user.city}, ${user.country}`}
|
||||||
<br />
|
<br />
|
||||||
|
|
@ -115,14 +118,16 @@ const JKProfileSidePanel = props => {
|
||||||
<h5>Interests</h5>
|
<h5>Interests</h5>
|
||||||
<JKProfileInterests user={user} />
|
<JKProfileInterests user={user} />
|
||||||
|
|
||||||
|
{ currentUser &&
|
||||||
|
|
||||||
<div className="p-3 bg-white border-top fixed-bottom">
|
<div className="p-3 bg-white border-top fixed-bottom">
|
||||||
<button className="btn btn-primary">
|
<JKConnectButton currentUser={currentUser} user={user} addContent={<><FontAwesomeIcon icon="plus" transform="shrink-4 down-1" className="mr-1" /> Add Friend </>} removeContent={<><FontAwesomeIcon icon="minus" transform="shrink-4 down-1" className="mr-1" /> Disconnect</>} />
|
||||||
<span className="fas fa-plus" /> Add Friend
|
{' '}
|
||||||
</button>{' '}
|
<button className="btn btn-outline-primary" data-testid="message">
|
||||||
<button className="btn btn-outline-primary">
|
|
||||||
<span className="fas fa-comment" /> Send Message
|
<span className="fas fa-comment" /> Send Message
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,22 @@
|
||||||
import { reject } from "lodash";
|
|
||||||
import apiFetch from "./apiFetch";
|
import apiFetch from "./apiFetch";
|
||||||
|
|
||||||
export const getPeople = () => {
|
export const getMusicians = (page) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
apiFetch("/search/musicians?results=true")
|
apiFetch(`/search/musicians?results=true`)
|
||||||
.then(response => resolve(response))
|
.then(response => resolve(response))
|
||||||
.catch(error => reject(error))
|
.catch(error => reject(error))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getUserProfile = (id) => {
|
// export const getPeople = (page) => {
|
||||||
|
// return new Promise((resolve, reject) => {
|
||||||
|
// apiFetch(`/filter?page=${page}`)
|
||||||
|
// .then(response => resolve(response))
|
||||||
|
// .catch(error => reject(error))
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
export const getPersonById = (id) => {
|
||||||
return new Promise((resolve, reject) => (
|
return new Promise((resolve, reject) => (
|
||||||
apiFetch(`/users/${id}/profile?show_teacher=true`)
|
apiFetch(`/users/${id}/profile?show_teacher=true`)
|
||||||
.then(response => resolve(response))
|
.then(response => resolve(response))
|
||||||
|
|
@ -17,9 +24,9 @@ export const getUserProfile = (id) => {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const postPeopleSearch = (data) => {
|
export const getPeople = ({ data, page } = {}) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
apiFetch("/filter", {
|
apiFetch(`/filter?page=${page}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(data)
|
body: JSON.stringify(data)
|
||||||
})
|
})
|
||||||
|
|
@ -51,3 +58,43 @@ export const getCurrentUser = () => {
|
||||||
.catch(error => reject(error))
|
.catch(error => reject(error))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const addFriend = (userId, friendId) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
apiFetch(`/users/${userId}/friend_requests`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({ friend_id: friendId })
|
||||||
|
})
|
||||||
|
.then(response => resolve(response))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const removeFriend = (userId, friendId) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
apiFetch(`/users/${userId}/friends/${friendId}`, {
|
||||||
|
method: 'DELETE'
|
||||||
|
})
|
||||||
|
.then(response => resolve(response))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getTextMessages = (options = {}) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
apiFetch(`/text_messages?${new URLSearchParams(options)}`)
|
||||||
|
.then(response => resolve(response))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createTextMessage = (options) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
apiFetch(`/text_messages`, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(options)
|
||||||
|
})
|
||||||
|
.then(response => resolve(response))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import React, { useContext, useEffect } from 'react';
|
import React, { useContext, useEffect } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Route, Switch, Redirect } from 'react-router-dom';
|
import { Route, Switch, Redirect, NavLink } from 'react-router-dom';
|
||||||
|
import { Card, CardBody, Row, Col, Button } from "reactstrap";
|
||||||
import Dashboard from '../components/dashboard/Dashboard';
|
import Logo from '../components/navbar/Logo';
|
||||||
|
import Section from '../components/common/Section';
|
||||||
|
//import Dashboard from '../components/dashboard/Dashboard';
|
||||||
import JKDashboard from '../components/dashboard/JkDashboard';
|
import JKDashboard from '../components/dashboard/JkDashboard';
|
||||||
//import DashboardAlt from '../components/dashboard-alt/DashboardAlt';
|
//import DashboardAlt from '../components/dashboard-alt/DashboardAlt';
|
||||||
|
|
||||||
|
|
@ -17,6 +19,7 @@ import ProductProvider from '../components/e-commerce/ProductProvider';
|
||||||
import { getPageName } from '../helpers/utils';
|
import { getPageName } from '../helpers/utils';
|
||||||
|
|
||||||
import { useAuth } from '../context/AuthContext';
|
import { useAuth } from '../context/AuthContext';
|
||||||
|
import { getCurrentUser } from '../helpers/rest';
|
||||||
|
|
||||||
const DashboardRoutes = loadable(() => import('./DashboardRoutes'));
|
const DashboardRoutes = loadable(() => import('./DashboardRoutes'));
|
||||||
|
|
||||||
|
|
@ -25,6 +28,26 @@ const DashboardLayout = ({ location }) => {
|
||||||
|
|
||||||
const isKanban = getPageName('kanban');
|
const isKanban = getPageName('kanban');
|
||||||
|
|
||||||
|
const {currentUser, setCurrentUser} = useAuth()
|
||||||
|
|
||||||
|
const fetchCurrentUser = () => {
|
||||||
|
getCurrentUser()
|
||||||
|
.then(resp => {
|
||||||
|
if (resp.ok) {
|
||||||
|
return resp.json();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
console.log('layout CURRENT_USER', data);
|
||||||
|
setCurrentUser(data);
|
||||||
|
})
|
||||||
|
.catch(error => console.log(error));
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchCurrentUser()
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
DashboardRoutes.preload();
|
DashboardRoutes.preload();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
@ -34,6 +57,26 @@ const DashboardLayout = ({ location }) => {
|
||||||
}, [location.pathname]);
|
}, [location.pathname]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
{ currentUser == null ? (
|
||||||
|
<Section className="py-0">
|
||||||
|
<Row className="flex-center min-vh-100 py-6">
|
||||||
|
<Col sm={10} md={8} lg={6} xl={5} className="col-xxl-4">
|
||||||
|
<Logo/>
|
||||||
|
<Card>
|
||||||
|
<CardBody className="fs--1 font-weight-normal p-5">
|
||||||
|
<Row className="justify-content-center">
|
||||||
|
<h3 className="mt-3 mt-md-4 font-weight-normal fs-2">Signin to begin</h3>
|
||||||
|
<p>Please login to your jamkazam account before accessing this interface.</p>
|
||||||
|
<a className="btn btn-primary" href="https://www.jamkazam.com/signin">Signin</a>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Section>
|
||||||
|
) : (
|
||||||
<div className={isFluid || isKanban ? 'container-fluid' : 'container'}>
|
<div className={isFluid || isKanban ? 'container-fluid' : 'container'}>
|
||||||
{isVertical && <NavbarVertical isKanban={isKanban} navbarStyle={navbarStyle} />}
|
{isVertical && <NavbarVertical isKanban={isKanban} navbarStyle={navbarStyle} />}
|
||||||
<ProductProvider>
|
<ProductProvider>
|
||||||
|
|
@ -51,6 +94,9 @@ const DashboardLayout = ({ location }) => {
|
||||||
{/* <SidePanelModal path={location.pathname} /> */}
|
{/* <SidePanelModal path={location.pathname} /> */}
|
||||||
</ProductProvider>
|
</ProductProvider>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
|
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
|
||||||
import { toast, ToastContainer } from 'react-toastify';
|
import { toast, ToastContainer } from 'react-toastify';
|
||||||
import { CloseButton, Fade } from '../components/common/Toast';
|
import { CloseButton, Fade } from '../components/common/Toast';
|
||||||
|
|
||||||
import DashboardLayout from './DashboardLayout';
|
import DashboardLayout from './DashboardLayout';
|
||||||
import ErrorLayout from './ErrorLayout';
|
import ErrorLayout from './ErrorLayout';
|
||||||
|
|
||||||
import loadable from '@loadable/component';
|
|
||||||
|
|
||||||
|
|
||||||
const AuthBasicLayout = loadable(() => import('./AuthBasicLayout'));
|
// import loadable from '@loadable/component';
|
||||||
|
|
||||||
|
//const AuthBasicLayout = loadable(() => import('./AuthBasicLayout'));
|
||||||
//const Landing = loadable(() => import('../components/landing/Landing'));
|
//const Landing = loadable(() => import('../components/landing/Landing'));
|
||||||
//const WizardLayout = loadable(() => import('../components/auth/wizard/WizardLayout'));
|
//const WizardLayout = loadable(() => import('../components/auth/wizard/WizardLayout'));
|
||||||
//const AuthCardRoutes = loadable(() => import('../components/auth/card/AuthCardRoutes'));
|
//const AuthCardRoutes = loadable(() => import('../components/auth/card/AuthCardRoutes'));
|
||||||
|
|
@ -17,31 +18,16 @@ const AuthBasicLayout = loadable(() => import('./AuthBasicLayout'));
|
||||||
|
|
||||||
const Layout = () => {
|
const Layout = () => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
AuthBasicLayout.preload();
|
//AuthBasicLayout.preload();
|
||||||
//Landing.preload();
|
//Landing.preload();
|
||||||
//WizardLayout.preload();
|
//WizardLayout.preload();
|
||||||
//AuthCardRoutes.preload();
|
//AuthCardRoutes.preload();
|
||||||
//AuthSplitRoutes.preload();
|
//AuthSplitRoutes.preload();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// async function fetchUserData(){
|
|
||||||
// await apiFetch('/users/current_user_data')
|
|
||||||
// .then(resp => {
|
|
||||||
// if(!resp.ok){
|
|
||||||
// //handle error
|
|
||||||
// console.log("fetchUserData failed", resp);
|
|
||||||
// }else{
|
|
||||||
// return resp.json()
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// .then(json => {
|
|
||||||
// setCurrentUser(json)
|
|
||||||
// console.log("USER>>>>>>>", json);
|
|
||||||
// })
|
|
||||||
// .catch(error => console.log(error))
|
|
||||||
// }
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Router fallback={<span />}>
|
<Router fallback={<span />}>
|
||||||
<Switch>
|
<Switch>
|
||||||
|
|
@ -51,10 +37,9 @@ const Layout = () => {
|
||||||
<Route path="/authentication/split" component={AuthSplitRoutes} />
|
<Route path="/authentication/split" component={AuthSplitRoutes} />
|
||||||
<Route path="/authentication/wizard" component={WizardLayout} /> */}
|
<Route path="/authentication/wizard" component={WizardLayout} /> */}
|
||||||
<Route path="/errors" component={ErrorLayout} />
|
<Route path="/errors" component={ErrorLayout} />
|
||||||
<Route path="/authentication/basic" component={AuthBasicLayout} />
|
{/* <Route path="/authentication/basic" component={AuthBasicLayout} /> */}
|
||||||
|
|
||||||
<Route component={DashboardLayout} />
|
<Route component={DashboardLayout} />
|
||||||
|
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|
||||||
<ToastContainer transition={Fade} closeButton={<CloseButton />} position={toast.POSITION.BOTTOM_LEFT} />
|
<ToastContainer transition={Fade} closeButton={<CloseButton />} position={toast.POSITION.BOTTOM_LEFT} />
|
||||||
|
|
@ -62,6 +47,4 @@ const Layout = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default Layout;
|
export default Layout;
|
||||||
|
|
|
||||||
|
|
@ -43,3 +43,4 @@ public/uploads
|
||||||
/log/*.out
|
/log/*.out
|
||||||
BUILD_NUMBER
|
BUILD_NUMBER
|
||||||
.byebug_history
|
.byebug_history
|
||||||
|
.ruby-version
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ class ApiSearchController < ApiController
|
||||||
|
|
||||||
respond_to :json
|
respond_to :json
|
||||||
|
|
||||||
|
include LatencyHelper
|
||||||
|
|
||||||
def index
|
def index
|
||||||
if 1 == params[Search::PARAM_MUSICIAN].to_i || 1 == params[Search::PARAM_BAND].to_i
|
if 1 == params[Search::PARAM_MUSICIAN].to_i || 1 == params[Search::PARAM_BAND].to_i
|
||||||
query = params.clone
|
query = params.clone
|
||||||
|
|
@ -93,8 +95,8 @@ class ApiSearchController < ApiController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
#filter users by first fetching users from latency graph database
|
#Filter users by first fetching users from latency graph database
|
||||||
#for the latency filter options and then quering the relational
|
#for latency specific filter options and then query the postgresql relational
|
||||||
#database for other filter options
|
#database for other filter options
|
||||||
def filter
|
def filter
|
||||||
latency_good = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_good])
|
latency_good = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_good])
|
||||||
|
|
@ -102,7 +104,9 @@ class ApiSearchController < ApiController
|
||||||
latency_high = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_high])
|
latency_high = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_high])
|
||||||
|
|
||||||
begin
|
begin
|
||||||
user_ids = user_ids_by_latency(latency_good, latency_fair, latency_high)
|
@latency_data = users_latency_data(latency_good, latency_fair, latency_high)
|
||||||
|
#debugger
|
||||||
|
user_ids = @latency_data.map{ |l_data| l_data[:user_id] }
|
||||||
|
|
||||||
filter_params = {
|
filter_params = {
|
||||||
"sort_order"=>"latency",
|
"sort_order"=>"latency",
|
||||||
|
|
@ -168,58 +172,73 @@ private
|
||||||
"#{Rails.application.config.latency_data_host}/search_users"
|
"#{Rails.application.config.latency_data_host}/search_users"
|
||||||
end
|
end
|
||||||
|
|
||||||
def user_ids_by_latency(latency_good, latency_fair, latency_high)
|
# def users_latency_data(latency_good, latency_fair, latency_high)
|
||||||
user_ids = []
|
# latency_data = []
|
||||||
if latency_good || latency_fair || latency_high
|
# if latency_good || latency_fair || latency_high
|
||||||
uri = URI(filter_latency_url)
|
# uri = URI(filter_latency_url)
|
||||||
begin
|
# begin
|
||||||
http = Net::HTTP.new(uri.host, uri.port)
|
# http = Net::HTTP.new(uri.host, uri.port)
|
||||||
http.use_ssl = true if Rails.application.config.latency_data_host.start_with?("https://")
|
# http.use_ssl = true if Rails.application.config.latency_data_host.start_with?("https://")
|
||||||
req = Net::HTTP::Post.new(uri)
|
# req = Net::HTTP::Post.new(uri)
|
||||||
req["Authorization"] = "Basic #{Rails.application.config.latency_data_host_auth_code}"
|
# req["Authorization"] = "Basic #{Rails.application.config.latency_data_host_auth_code}"
|
||||||
req["Content-Type"] = "application/json"
|
# req["Content-Type"] = "application/json"
|
||||||
req.body = {
|
# req.body = {
|
||||||
my_user_id: current_user.id,
|
# my_user_id: current_user.id,
|
||||||
my_public_ip: request.remote_ip,
|
# my_public_ip: request.remote_ip,
|
||||||
my_device_id: nil,
|
# my_device_id: nil,
|
||||||
my_client_id: nil
|
# my_client_id: nil
|
||||||
}.to_json
|
# }.to_json
|
||||||
|
|
||||||
response = http.request(req)
|
# response = http.request(req)
|
||||||
|
|
||||||
if response.is_a?(Net::HTTPOK) || response.is_a?(Net::HTTPSuccess)
|
# if response.is_a?(Net::HTTPOK) || response.is_a?(Net::HTTPSuccess)
|
||||||
graph_db_users = JSON.parse(response.body)["users"]
|
# graph_db_users = JSON.parse(response.body)["users"]
|
||||||
if latency_good || latency_fair || latency_high
|
# if latency_good || latency_fair || latency_high
|
||||||
graph_db_users.select! do |user|
|
# graph_db_users.select! do |user|
|
||||||
total_latency = user["ars"]["total_latency"].to_f
|
# total_latency = user["ars"]["total_latency"].to_f
|
||||||
(total_latency <= 40 && latency_good) ||
|
# (total_latency >= 0 && total_latency <= 40 && latency_good) ||
|
||||||
(total_latency > 40 && total_latency <= 80 && latency_fair) ||
|
# (total_latency > 40 && total_latency <= 80 && latency_fair) ||
|
||||||
(total_latency > 80 && latency_high)
|
# (total_latency > 80 && latency_high)
|
||||||
end
|
# end
|
||||||
end
|
# end
|
||||||
|
|
||||||
user_ids = graph_db_users.map { | user | user["user_id"] }.uniq
|
# latency_data = graph_db_users.map { | user |
|
||||||
|
# total = user["ars"]["total_latency"].to_f
|
||||||
return user_ids
|
# label = if total >= 0 && total <= 40
|
||||||
else
|
# 'good'
|
||||||
logger.debug("Latency response failed: #{response}")
|
# elsif total > 40 && total <= 80
|
||||||
Bugsnag.notify("LatencyResponseFailed") do |report|
|
# 'fair'
|
||||||
report.severity = "faliure"
|
# else
|
||||||
report.add_tab(:latency, {
|
# 'high'
|
||||||
user_id: current_user.id,
|
# end
|
||||||
name: current_user.name,
|
# {
|
||||||
params: params,
|
# user_id: user["user_id"],
|
||||||
url: filter_latency_url,
|
# audio_latency: user["audio_latency"].to_f,
|
||||||
code: response.code,
|
# ars_total_latency: user["ars"]["total_latency"].to_f,
|
||||||
body: response.body,
|
# ars_internet_latency: user["ars"]["internet_latency"].to_f
|
||||||
})
|
# }
|
||||||
end
|
# }.uniq
|
||||||
end
|
# #debugger
|
||||||
rescue => exception
|
# return latency_data
|
||||||
raise exception
|
# else
|
||||||
end
|
# logger.debug("Latency response failed: #{response}")
|
||||||
end
|
# Bugsnag.notify("LatencyResponseFailed") do |report|
|
||||||
user_ids
|
# report.severity = "faliure"
|
||||||
end
|
# 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
|
||||||
|
# end
|
||||||
|
# rescue => exception
|
||||||
|
# raise exception
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# latency_data
|
||||||
|
# end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ class ApiUsersController < ApiController
|
||||||
end
|
end
|
||||||
|
|
||||||
def me
|
def me
|
||||||
render json: { first_name: current_user.first_name, last_name: current_user.last_name, name: current_user.name, photo_url: current_user.photo_url }, status: 200
|
render json: { id: current_user.id, first_name: current_user.first_name, last_name: current_user.last_name, name: current_user.name, photo_url: current_user.photo_url }, status: 200
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,153 @@
|
||||||
|
module LatencyHelper
|
||||||
|
LATENCY_SCORES = {
|
||||||
|
good: { label: 'GOOD', min: 0, max: 40 },
|
||||||
|
fair: { label: 'FAIR', min: 40, max: 80 },
|
||||||
|
high: { label: 'HIGH', min: 80, max: 10000000 },
|
||||||
|
me: { label: 'ME', min: -1, max: -1 },
|
||||||
|
unknown: { label: 'UNKNOWN', min: -2, max: -2 }
|
||||||
|
}
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# response = http.request(req)
|
||||||
|
|
||||||
|
# if response.is_a?(Net::HTTPOK) || response.is_a?(Net::HTTPSuccess)
|
||||||
|
# graph_db_users = JSON.parse(response.body)["users"]
|
||||||
|
# if latency_good || latency_fair || latency_high
|
||||||
|
# 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 |
|
||||||
|
# total = user["ars"]["total_latency"].to_f
|
||||||
|
# label = if total >= LATENCY_SCORES[:good][:min] && total <= LATENCY_SCORES[:good][:max]
|
||||||
|
# LATENCY_SCORES[:good][:label]
|
||||||
|
# elsif total > LATENCY_SCORES[:fair][:min] && total <= LATENCY_SCORES[:fair][:max]
|
||||||
|
# LATENCY_SCORES[:fair][:label]
|
||||||
|
# elsif total > LATENCY_SCORES[:high][:min]
|
||||||
|
# LATENCY_SCORES[:high][:label]
|
||||||
|
# else
|
||||||
|
# LATENCY_SCORES[:unknown][:label]
|
||||||
|
# end
|
||||||
|
# {
|
||||||
|
# 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,
|
||||||
|
# label: label
|
||||||
|
# }
|
||||||
|
# }.uniq
|
||||||
|
# #debugger
|
||||||
|
# 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
|
||||||
|
# end
|
||||||
|
# rescue => exception
|
||||||
|
# raise exception
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# latency_data
|
||||||
|
# end
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
response = http.request(req)
|
||||||
|
|
||||||
|
if response.is_a?(Net::HTTPOK) || response.is_a?(Net::HTTPSuccess)
|
||||||
|
graph_db_users = JSON.parse(response.body)["users"]
|
||||||
|
if latency_good || latency_fair || latency_high
|
||||||
|
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 |
|
||||||
|
total = user["ars"]["total_latency"].to_f
|
||||||
|
label = if total >= LATENCY_SCORES[:good][:min] && total <= LATENCY_SCORES[:good][:max]
|
||||||
|
LATENCY_SCORES[:good][:label]
|
||||||
|
elsif total > LATENCY_SCORES[:fair][:min] && total <= LATENCY_SCORES[:fair][:max]
|
||||||
|
LATENCY_SCORES[:fair][:label]
|
||||||
|
elsif total > LATENCY_SCORES[:high][:min]
|
||||||
|
LATENCY_SCORES[:high][:label]
|
||||||
|
else
|
||||||
|
LATENCY_SCORES[:unknown][:label]
|
||||||
|
end
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
label: label
|
||||||
|
}
|
||||||
|
}.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
|
||||||
|
end
|
||||||
|
rescue => exception
|
||||||
|
raise exception
|
||||||
|
end
|
||||||
|
end
|
||||||
|
latency_data
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
@ -60,6 +60,17 @@ if @search.is_a?(BaseSearch)
|
||||||
node :audio_latency do |musician|
|
node :audio_latency do |musician|
|
||||||
last_jam_audio_latency(musician)
|
last_jam_audio_latency(musician)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
node :latency_data do |musician|
|
||||||
|
|
||||||
|
if latency = @latency_data.detect{|l_data| l_data[:user_id] == musician.id }
|
||||||
|
{
|
||||||
|
audio_latency: latency[:audio_latency],
|
||||||
|
ars_internet_latency: latency[:ars_internet_latency],
|
||||||
|
ars_total_latency: latency[:ars_total_latency]
|
||||||
|
}
|
||||||
|
end if @latency_data
|
||||||
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif @search.is_a?(BandSearch)
|
elsif @search.is_a?(BandSearch)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Rails.application.config.middleware.insert_before 0, Rack::Cors do
|
||||||
|
|
||||||
resource '*',
|
resource '*',
|
||||||
headers: :any,
|
headers: :any,
|
||||||
methods: [:get, :post, :options],
|
methods: [:get, :post, :delete, :options],
|
||||||
credentials: true
|
credentials: true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -10,16 +10,18 @@ describe "Musician Filter API", type: :request do
|
||||||
let(:user4) { FactoryGirl.create(:user) }
|
let(:user4) { FactoryGirl.create(:user) }
|
||||||
let(:user5) { FactoryGirl.create(:user) }
|
let(:user5) { FactoryGirl.create(:user) }
|
||||||
let(:user6) { FactoryGirl.create(:user) }
|
let(:user6) { FactoryGirl.create(:user) }
|
||||||
|
let(:user7) { FactoryGirl.create(:user) }
|
||||||
|
|
||||||
let(:latency_data_uri) { /\S+\/search_users/ }
|
let(:latency_data_uri) { /\S+\/search_users/ }
|
||||||
|
|
||||||
let(:response_body) { mock_latency_response([
|
let(:response_body) { mock_latency_response([
|
||||||
{ user: user1, ars_total_latency: 1.0, ars_internet_latency: 0.4, audio_latency: 0.6 }, #GOOD
|
{ user: user1, ars_total_latency: 1.0, ars_internet_latency: 0.4, audio_latency: 0.6 }, #GOOD
|
||||||
{ user: user2, ars_total_latency: 40.0, ars_internet_latency: 25.0, audio_latency: 15.0 }, #GOOD
|
{ user: user2, ars_total_latency: 40.0, ars_internet_latency: 25.0, audio_latency: 15.0 }, #GOOD
|
||||||
{ user: user3, ars_total_latency: 41.0, ars_internet_latency: 25, audio_latency: 16 }, #FAIR
|
{ user: user3, ars_total_latency: 40.1, ars_internet_latency: 25, audio_latency: 15.1 }, #FAIR
|
||||||
{ user: user4, ars_total_latency: 80.0, ars_internet_latency: 40, audio_latency: 40.0 }, #FAIR
|
{ user: user4, ars_total_latency: 80.0, ars_internet_latency: 40, audio_latency: 40.0 }, #FAIR
|
||||||
{ user: user5, ars_total_latency: 81.0, ars_internet_latency: 41, audio_latency: 40 }, #HIGH
|
{ user: user5, ars_total_latency: 80.1, ars_internet_latency: 40.1, audio_latency: 40 }, #HIGH
|
||||||
{ user: user6, ars_total_latency: 100.0, ars_internet_latency: 50.0, audio_latency: 50.0 } #HIGH
|
{ user: user6, ars_total_latency: 100.0, ars_internet_latency: 50.0, audio_latency: 50.0 }, #HIGH
|
||||||
|
{ user: user7, ars_total_latency: -2, ars_internet_latency: -1, audio_latency: -1 } #UNKNOWN
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -28,7 +30,6 @@ describe "Musician Filter API", type: :request do
|
||||||
let(:rock) { Genre.find_by_id('rock') }
|
let(:rock) { Genre.find_by_id('rock') }
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
#ActiveMusicSession.delete_all
|
|
||||||
User.delete_all
|
User.delete_all
|
||||||
stub_request(:post, latency_data_uri)
|
stub_request(:post, latency_data_uri)
|
||||||
.with(:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json', 'User-Agent'=>'Ruby'})
|
.with(:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json', 'User-Agent'=>'Ruby'})
|
||||||
|
|
@ -45,20 +46,27 @@ describe "Musician Filter API", type: :request do
|
||||||
|
|
||||||
it "get all musicians" do
|
it "get all musicians" do
|
||||||
get '/api/search/musicians.json?results=true'
|
get '/api/search/musicians.json?results=true'
|
||||||
expect(JSON.parse(response.body)["musicians"].size).to eq(6)
|
expect(JSON.parse(response.body)["musicians"].size).to eq(7)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "filter all musicians for all latency types" do
|
it "filter all musicians for all latency types" do
|
||||||
post '/api/filter.json', { latency_good: false, latency_fair: false, latency_high: false }
|
post '/api/filter.json', { latency_good: false, latency_fair: false, latency_high: false }
|
||||||
expect(JSON.parse(response.body)["musicians"].size).to eq(6)
|
expect(JSON.parse(response.body)["musicians"].size).to eq(7)
|
||||||
|
expect(JSON.parse(response.body)["musicians"][0]["latency_data"]).to eq(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "filter GOOD latency users" do
|
it "filter GOOD latency users", focus: true do
|
||||||
post '/api/filter.json', { latency_good: true, latency_fair: false, latency_high: false }
|
post '/api/filter.json', { latency_good: true, latency_fair: false, latency_high: false }
|
||||||
expect(response.content_type).to eq("application/json")
|
expect(response.content_type).to eq("application/json")
|
||||||
expect(response).to render_template(:index)
|
expect(response).to render_template(:index)
|
||||||
expect(response).to have_http_status(:created)
|
expect(response).to have_http_status(:created)
|
||||||
expect(JSON.parse(response.body)["musicians"].size).to eq(2)
|
expect(JSON.parse(response.body)["musicians"].size).to eq(2)
|
||||||
|
|
||||||
|
#test latency data
|
||||||
|
expect(JSON.parse(response.body)["musicians"][0]["latency_data"]).not_to eq(nil)
|
||||||
|
expect(JSON.parse(response.body)["musicians"][0]["latency_data"]["audio_latency"]).not_to eq(nil)
|
||||||
|
expect(JSON.parse(response.body)["musicians"][0]["latency_data"]["ars_internet_latency"]).not_to eq(nil)
|
||||||
|
expect(JSON.parse(response.body)["musicians"][0]["latency_data"]["ars_total_latency"]).not_to eq(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "filter FAIR latency musicians" do
|
it "filter FAIR latency musicians" do
|
||||||
|
|
@ -120,7 +128,7 @@ describe "Musician Filter API", type: :request do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "filter musicians by instruments they play", focus: true do
|
it "filter musicians by instruments they play" do
|
||||||
user1.musician_instruments << FactoryGirl.create(:musician_instrument, player: user1, instrument: JamRuby::Instrument.find('drums'), proficiency_level: 1 )
|
user1.musician_instruments << FactoryGirl.create(:musician_instrument, player: user1, instrument: JamRuby::Instrument.find('drums'), proficiency_level: 1 )
|
||||||
user1.musician_instruments << FactoryGirl.create(:musician_instrument, player: user1, instrument: JamRuby::Instrument.find('violin'), proficiency_level: 2 )
|
user1.musician_instruments << FactoryGirl.create(:musician_instrument, player: user1, instrument: JamRuby::Instrument.find('violin'), proficiency_level: 2 )
|
||||||
user1.save!
|
user1.save!
|
||||||
|
|
@ -144,7 +152,7 @@ describe "Musician Filter API", type: :request do
|
||||||
expect(JSON.parse(response.body)["musicians"].size).to eq(0)
|
expect(JSON.parse(response.body)["musicians"].size).to eq(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "filter musicians by joined within day" do
|
it "filter musicians by days ago that they joined" do
|
||||||
user1.created_at = 1.day.ago
|
user1.created_at = 1.day.ago
|
||||||
user1.save!
|
user1.save!
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,3 +26,4 @@ target
|
||||||
vendor
|
vendor
|
||||||
BUILD_NUMBER
|
BUILD_NUMBER
|
||||||
.byebug_history
|
.byebug_history
|
||||||
|
.ruby-version
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue