UI changes as per the requests by David
This commit is contained in:
parent
e769eb0531
commit
2110c4b1ce
|
|
@ -18,7 +18,8 @@
|
|||
{ "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 }
|
||||
{ "instrument_id": "piano", "description": "Piano", "proficiency_level": 2, "priority": 10 },
|
||||
{ "instrument_id": "banjo", "description": "Banjo", "proficiency_level": 2, "priority": 4}
|
||||
],
|
||||
"followings": [],
|
||||
"is_friend": true,
|
||||
|
|
@ -29,7 +30,33 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 10,
|
||||
"audio_latency": 5,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": [
|
||||
{
|
||||
"description": "Asian"
|
||||
},
|
||||
{
|
||||
"description": "Classical"
|
||||
},
|
||||
{
|
||||
"description": "Hard Rock"
|
||||
},
|
||||
{
|
||||
"description": "Jazz"
|
||||
},
|
||||
{
|
||||
"description": "Latin"
|
||||
},
|
||||
{
|
||||
"description": "Oldies"
|
||||
},
|
||||
{
|
||||
"description": "Pop"
|
||||
},
|
||||
{
|
||||
"description": "Soft Rock"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
|
|
@ -56,7 +83,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
|
|
@ -83,7 +111,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "4",
|
||||
|
|
@ -110,7 +139,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "5",
|
||||
|
|
@ -137,7 +167,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "6",
|
||||
|
|
@ -164,7 +195,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "7",
|
||||
|
|
@ -191,7 +223,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "8",
|
||||
|
|
@ -218,7 +251,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "9",
|
||||
|
|
@ -245,7 +279,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "10",
|
||||
|
|
@ -272,7 +307,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
|
||||
{
|
||||
|
|
@ -304,7 +340,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 10,
|
||||
"audio_latency": 5,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "12",
|
||||
|
|
@ -331,7 +368,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "13",
|
||||
|
|
@ -358,7 +396,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "14",
|
||||
|
|
@ -385,7 +424,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "15",
|
||||
|
|
@ -412,7 +452,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "16",
|
||||
|
|
@ -439,7 +480,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "17",
|
||||
|
|
@ -466,7 +508,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "18",
|
||||
|
|
@ -493,7 +536,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "19",
|
||||
|
|
@ -520,7 +564,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
},
|
||||
{
|
||||
"id": "20",
|
||||
|
|
@ -547,7 +592,8 @@
|
|||
"recording_count": 0,
|
||||
"session_count": 0,
|
||||
"audio_latency": null,
|
||||
"last_active_timestamp": 1629916641
|
||||
"last_active_timestamp": 1629916641,
|
||||
"genres": []
|
||||
}
|
||||
],
|
||||
"page_count": 2,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,43 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
const showSidePanelContent = () => {
|
||||
cy.get('[data-testid=profileSidePanel] h4').should('have.text', 'Test User1');
|
||||
cy.get('[data-testid=profileSidePanel] .modal-body p').within(() => {
|
||||
cy.contains('Location: Denver, US')
|
||||
.and('contain', 'Location: Denver, US')
|
||||
.and('contain', 'Skill Level: Professional')
|
||||
.and('contain', 'Joined JamKazam: 08-26-2021')
|
||||
.and('contain', 'Last Active:')
|
||||
.and('contain', 'Latency To Me:');
|
||||
cy.get('.latency-badge').contains('UNKNOWN');
|
||||
});
|
||||
|
||||
cy.get('[data-testid=profileSidePanel] .modal-body').within(() => {
|
||||
cy.get('[data-testid=biography]').contains('Biography of Test User1');
|
||||
|
||||
//instruments
|
||||
cy.get('[data-testid=instruments]').contains('Acoustic Guitar: Expert');
|
||||
cy.get('[data-testid=instruments]').contains('Keyboard: Expert');
|
||||
|
||||
//genres
|
||||
cy.get('[data-testid=genres]').contains('classical, blues');
|
||||
|
||||
//bands
|
||||
cy.get('[data-testid=bands]').contains('The Band');
|
||||
|
||||
//performance_samples
|
||||
//cy.get('[data-testid=performance_samples]').contains('The Band')
|
||||
|
||||
//online presence
|
||||
cy.get('[data-testid=online_presences]').contains('Soundcloud');
|
||||
cy.get('[data-testid=online_presences]').contains('Reverbnation');
|
||||
});
|
||||
};
|
||||
|
||||
const closeSidePanel = () => {
|
||||
cy.get('[data-testid=profileSidePanel] .modal-header button.close').click();
|
||||
};
|
||||
|
||||
describe('Friends page without data', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate();
|
||||
|
|
@ -18,6 +56,7 @@ describe('Friends page with data', () => {
|
|||
beforeEach(() => {
|
||||
cy.stubAuthenticate({ id: '2' }); //currentUser id is 2 - people.yaml fixture
|
||||
cy.intercept('POST', /\S+\/filter/, { fixture: 'people' }).as('getPeople');
|
||||
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
|
||||
});
|
||||
|
||||
describe('listing users', () => {
|
||||
|
|
@ -25,88 +64,138 @@ describe('Friends page with data', () => {
|
|||
cy.visit('/friends');
|
||||
});
|
||||
|
||||
it('lists musician users', () => {
|
||||
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');
|
||||
});
|
||||
describe('in desktop', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport('macbook-13');
|
||||
});
|
||||
|
||||
it('show profiles', () => {
|
||||
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');
|
||||
});
|
||||
|
||||
it('click profile name', () => {
|
||||
//open side panel by clicking name
|
||||
cy.get('[data-testid=peopleListTable]').within(() => {
|
||||
cy.contains('Test User1').click();
|
||||
});
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click more button', () => {
|
||||
//open side panel by clicking more button
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('[data-testid=btnMore]')
|
||||
.click();
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click more link', () => {
|
||||
//open side panel by clicking more link
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('[data-testid=linkMore]')
|
||||
.click();
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click description more link', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('td[data-testid=biography-col]')
|
||||
.within(() => {
|
||||
cy.contains('More').click();
|
||||
});
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click instruments more link', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('td[data-testid=instruments-col]')
|
||||
.within(() => {
|
||||
cy.get('div').should('have.length', 4); //show only 4 instruments plus more link
|
||||
cy.contains('Acoustic Guitar: Expert');
|
||||
cy.contains('Keyboard: Expert');
|
||||
cy.contains('Ukulele: Expert');
|
||||
cy.contains('Voice: Expert');
|
||||
cy.contains('More').click();
|
||||
});
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click genres more link', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('td[data-testid=genres-col]')
|
||||
.within(() => {
|
||||
cy.contains('More').click();
|
||||
});
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
})
|
||||
|
||||
describe('in mobile', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport('iphone-6');
|
||||
});
|
||||
|
||||
it('show profile', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide').should('have.length', 20)
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide').eq(0).contains('Test User1')
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide').eq(0).should('be.visible')
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide').eq(2).should('not.be.visible')
|
||||
})
|
||||
|
||||
it('show all profile description', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide').first()
|
||||
.find('[data-testid=mobBiography]').should('not.contain', 'More')
|
||||
})
|
||||
|
||||
it('show all instruments', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide').first().find('[data-testid=instrumentList] div').its('length').should('be.gte', 1)
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide').first()
|
||||
.find('[data-testid=instrumentList]').should('not.contain', 'More')
|
||||
})
|
||||
|
||||
it('show all genres', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide').first().find('[data-testid=genreList] div').its('length').should('be.gte', 1)
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide').first()
|
||||
.find('[data-testid=genreList]').should('not.contain', 'More')
|
||||
})
|
||||
|
||||
it('click more button', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=btnMore]')
|
||||
.click();
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
})
|
||||
|
||||
it('click connect button', () => {})
|
||||
|
||||
it('click message button', () => {})
|
||||
|
||||
})
|
||||
|
||||
//TODO: paginate
|
||||
});
|
||||
|
||||
describe('user details side panel', () => {
|
||||
const showSidePanelContent = () => {
|
||||
cy.get('[data-testid=profileSidePanel] h4').should('have.text', 'Test User1');
|
||||
cy.get('[data-testid=profileSidePanel] .modal-body p').within(() => {
|
||||
cy.contains('Location: Denver, US')
|
||||
.and('contain', 'Location: Denver, US')
|
||||
.and('contain', 'Skill Level: Professional')
|
||||
.and('contain', 'Joined JamKazam: 08-26-2021')
|
||||
.and('contain', 'Last Active:')
|
||||
.and('contain', 'Latency to Me:');
|
||||
cy.get('.latency-badge').contains('UNKNOWN');
|
||||
});
|
||||
|
||||
cy.get('[data-testid=profileSidePanel] .modal-body').within(() => {
|
||||
cy.get('[data-testid=biography]').contains('Biography of Test User1');
|
||||
|
||||
//instruments
|
||||
cy.get('[data-testid=instruments]').contains('Acoustic Guitar: Expert');
|
||||
cy.get('[data-testid=instruments]').contains('Keyboard: Expert');
|
||||
|
||||
//genres
|
||||
cy.get('[data-testid=genres]').contains('classical, blues');
|
||||
|
||||
//bands
|
||||
cy.get('[data-testid=bands]').contains('The Band');
|
||||
|
||||
//performance_samples
|
||||
//cy.get('[data-testid=performance_samples]').contains('The Band')
|
||||
|
||||
//online presence
|
||||
cy.get('[data-testid=online_presences]').contains('Soundcloud');
|
||||
cy.get('[data-testid=online_presences]').contains('Reverbnation');
|
||||
});
|
||||
};
|
||||
|
||||
const closeSidePanel = () => {
|
||||
cy.get('[data-testid=profileSidePanel] .modal-header button.close').click();
|
||||
};
|
||||
|
||||
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();
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
|
||||
//open side panel by clicking more button
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('[data-testid=btnMore]')
|
||||
.click();
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
|
||||
//open side panel by clicking more link
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('[data-testid=linkMore]')
|
||||
.click();
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
});
|
||||
|
||||
describe('making friendship', () => {
|
||||
|
||||
describe.only('making friendship', () => {
|
||||
it('add friend', () => {
|
||||
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
|
||||
cy.intercept('POST', /\S+\/friend_requests/, { statusCode: 201, body: { ok: true } });
|
||||
|
|
@ -118,16 +207,15 @@ describe('Friends page with data', () => {
|
|||
.find('[data-testid=connect]')
|
||||
.should('not.be.disabled')
|
||||
.click();
|
||||
cy.get('[data-testid=confirmFriendRequestModal]')
|
||||
.within(() => {
|
||||
cy.contains('Send a friend request to Test User2')
|
||||
cy.contains('Yes').click()
|
||||
})
|
||||
|
||||
// cy.get('[data-testid=confirmFriendRequestModal]').within(() => {
|
||||
// cy.contains('Send a friend request to Test User2');
|
||||
// cy.contains('Yes').click();
|
||||
// });
|
||||
|
||||
cy.get('[data-testid=profileSidePanel]')
|
||||
.find('[data-testid=connect]')
|
||||
.should('be.disabled');
|
||||
cy.contains('Friend request was sent');
|
||||
cy.contains('Success! Your friend request has been sent to Test User2.');
|
||||
});
|
||||
|
||||
it('remove friend', () => {
|
||||
|
|
@ -291,7 +379,8 @@ describe('Friends page with data', () => {
|
|||
.click();
|
||||
cy.get('#selLastActive').type('Within last 1 Day{enter}');
|
||||
cy.get('#selJoinedWithin').type('Within last 7 Day{enter}');
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
cy.visit('/friends');
|
||||
});
|
||||
|
|
@ -305,21 +394,30 @@ describe('Friends page with data', () => {
|
|||
cy.get('[data-testid=modalUpdateSearch]').should('not.be.visible');
|
||||
});
|
||||
|
||||
it('render filter form', () => {
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.get('[data-testid=modalUpdateSearch]').within(() => {
|
||||
cy.get('input[name=latency_good]').should('be.checked').next().contains('Good (less than 40ms)')
|
||||
cy.get('input[name=latency_fair]').should('be.checked').next().contains('Fair (40-60ms)')
|
||||
cy.get('input[name=latency_high]').should('not.be.checked').next().contains('Poor (more than 60ms)')
|
||||
})
|
||||
})
|
||||
|
||||
it('reset filters', () => {
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
fillFilterForm()
|
||||
fillFilterForm();
|
||||
cy.get('[data-testid=modalUpdateSearch]')
|
||||
.contains('Cancel')
|
||||
.click();
|
||||
.contains('Cancel')
|
||||
.click();
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=latency_good]').should('not.be.checked')
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=latency_good]').should('not.be.checked');
|
||||
cy.get('[data-testid=modalUpdateSearch]')
|
||||
.contains('Cancel')
|
||||
.click();
|
||||
cy.get('[data-testid=btnResetSearch]').click() //click reset button
|
||||
.contains('Cancel')
|
||||
.click();
|
||||
cy.get('[data-testid=btnResetSearch]').click(); //click reset button
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=latency_good]').should('be.checked')
|
||||
})
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=latency_good]').should('be.checked');
|
||||
});
|
||||
|
||||
it('submit filter form with params', () => {
|
||||
//wait for stubbed request sent to fetch data for initial page load
|
||||
|
|
@ -338,7 +436,7 @@ describe('Friends page with data', () => {
|
|||
.should('deep.equal', {
|
||||
latency_good: true,
|
||||
latency_fair: true,
|
||||
latency_high: true,
|
||||
latency_high: false,
|
||||
proficiency_beginner: true,
|
||||
proficiency_intermediate: true,
|
||||
proficiency_expert: true,
|
||||
|
|
@ -346,8 +444,8 @@ describe('Friends page with data', () => {
|
|||
genres: []
|
||||
});
|
||||
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
fillFilterForm()
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
fillFilterForm();
|
||||
cy.get('[data-testid=btnSubmitSearch]').click();
|
||||
|
||||
//wait for stubbed request sent by submitting search form again. but this time fill form fields
|
||||
|
|
@ -370,4 +468,6 @@ describe('Friends page with data', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,18 +11,25 @@ describe("Top Navigation", () => {
|
|||
cy.get('[data-testid=navbarTopProfileDropdown]').should('exist')
|
||||
cy.contains("Peter Pan").should('exist')
|
||||
//cy.contains("My Profile").should('exist')
|
||||
cy.contains("Sign out").should('exist')
|
||||
cy.contains("Sign Out").should('exist')
|
||||
}
|
||||
|
||||
describe("when user has not logged in", () => {
|
||||
beforeEach(() => {
|
||||
cy.stubUnauthenticate()
|
||||
cy.visit('/')
|
||||
});
|
||||
|
||||
it("does not show user dropdown", () => {
|
||||
cy.contains("Sign in to begin")
|
||||
cy.get('a.btn').should('have.text', 'Sign in')
|
||||
it('shows homepage', () => {
|
||||
cy.visit('/')
|
||||
cy.contains('Home').should('exist')
|
||||
showSubscribeToUpdates()
|
||||
})
|
||||
|
||||
it("not allowed to projected page", () => {
|
||||
cy.visit('/friends')
|
||||
cy.url().should('include', '/authentication/basic/login')
|
||||
cy.contains("Sign in")
|
||||
cy.get('button').should('have.text', 'Sign in')
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]').should('not.exist')
|
||||
});
|
||||
|
||||
|
|
@ -36,17 +43,15 @@ describe("Top Navigation", () => {
|
|||
});
|
||||
|
||||
it("shows user dropdown", () => {
|
||||
showSubscribeToUpdates()
|
||||
showProfileDropdown()
|
||||
})
|
||||
|
||||
it('sign out', () => {
|
||||
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]').contains('Peter Pan').trigger('mouseover')
|
||||
cy.stubUnauthenticate()
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]').contains('Sign out').click()
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]').contains('Sign Out').click()
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]').should('not.exist')
|
||||
cy.contains("Sign in to begin")
|
||||
cy.contains("Home")
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -75,12 +80,12 @@ describe("Top Navigation", () => {
|
|||
})
|
||||
|
||||
it("translate", () => {
|
||||
cy.get('.card-header').contains('Home page')
|
||||
cy.get('.card-header').contains('Home')
|
||||
cy.get('[data-testid=langSwitch]').contains('ES').click()
|
||||
cy.get('.card-header').contains('Página de inicio')
|
||||
cy.get('.card-header').should('not.contain', 'Home page')
|
||||
cy.get('.card-header').should('not.contain', 'Home')
|
||||
cy.get('[data-testid=langSwitch]').contains('EN').click()
|
||||
cy.get('.card-header').contains('Home page')
|
||||
cy.get('.card-header').contains('Home')
|
||||
cy.get('.card-header').should('not.contain', 'Página de inicio')
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1264,6 +1264,15 @@
|
|||
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz",
|
||||
"integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
|
||||
},
|
||||
"@farfetch/react-context-responsive": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@farfetch/react-context-responsive/-/react-context-responsive-1.5.0.tgz",
|
||||
"integrity": "sha512-vroOutgYik9ts/RxCKcK0O+0QUOZNe5yU2OSbvuzsT9OvNprmHUFa502DQP3BcKF5mwdPQCI9V7LDUzQyxraMw==",
|
||||
"requires": {
|
||||
"css-mediaquery": "^0.1.2",
|
||||
"prop-types": "^15.6.1"
|
||||
}
|
||||
},
|
||||
"@fortawesome/fontawesome-common-types": {
|
||||
"version": "0.2.35",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.35.tgz",
|
||||
|
|
@ -6134,6 +6143,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"css-mediaquery": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz",
|
||||
"integrity": "sha1-aiw3NEkoYYYxxUvTPO3TAdoYvqA="
|
||||
},
|
||||
"css-prefers-color-scheme": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
"version": "2.10.2",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@farfetch/react-context-responsive": "^1.5.0",
|
||||
"@fortawesome/fontawesome-free": "^5.15.1",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.30",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.14.0",
|
||||
|
|
|
|||
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
|
|
@ -8,8 +8,25 @@ import { getItemFromStore, setItemToStore, themeColors } from './helpers/utils';
|
|||
import store from './store/store';
|
||||
import { Provider } from 'react-redux';
|
||||
import { CookiesProvider } from 'react-cookie';
|
||||
import { ResponsiveProvider } from '@farfetch/react-context-responsive';
|
||||
|
||||
const Main = props => {
|
||||
const breakpoints = {
|
||||
xs: '320px',
|
||||
sm: '576px',
|
||||
md: '960px',
|
||||
lg: '1280px',
|
||||
xl: '1800px'
|
||||
};
|
||||
|
||||
const breakpointsMax = {
|
||||
xs: '319px',
|
||||
sm: '575px',
|
||||
md: '959px',
|
||||
lg: '1279px',
|
||||
xl: '1799px'
|
||||
};
|
||||
|
||||
const [isFluid, setIsFluid] = useState(getItemFromStore('isFluid', settings.isFluid));
|
||||
const [isRTL, setIsRTL] = useState(getItemFromStore('isRTL', settings.isRTL));
|
||||
const [isDark, setIsDark] = useState(getItemFromStore('isDark', settings.isDark));
|
||||
|
|
@ -120,9 +137,11 @@ const Main = props => {
|
|||
|
||||
return (
|
||||
<AppContext.Provider value={value}>
|
||||
<CookiesProvider>
|
||||
<Provider store={store}>{props.children}</Provider>
|
||||
</CookiesProvider>
|
||||
<ResponsiveProvider breakpoints={breakpoints} breakpointsMax={breakpointsMax}>
|
||||
<CookiesProvider>
|
||||
<Provider store={store}>{props.children}</Provider>
|
||||
</CookiesProvider>
|
||||
</ResponsiveProvider>
|
||||
</AppContext.Provider>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@
|
|||
// 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;
|
||||
$jk-navigation-text-color: #5e6e82 !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;
|
||||
$navbar-light-color: rgba($jk-navigation-link-color, 1) !default;
|
||||
|
||||
$navbar-light-hover-color: darken($jk-navigation-link-color, 15) !default;
|
||||
|
|
@ -6,4 +6,4 @@
|
|||
|
||||
@import './custom/nav';
|
||||
@import './custom/user';
|
||||
@import './custom/form';
|
||||
@import './custom/form';
|
||||
|
|
|
|||
|
|
@ -10,4 +10,11 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// .navbar-top .navbar-nav a{
|
||||
// &:hover{
|
||||
// color: #1a993a !important;
|
||||
// }
|
||||
|
||||
// }
|
||||
|
|
@ -29,6 +29,8 @@ const LoginForm = ({ setRedirect, hasLabel, layout }) => {
|
|||
setCurrentUser(user)
|
||||
//localStorage.setItem('user', user)
|
||||
toast.success(`Signed in as ${email}`);
|
||||
setEmail('')
|
||||
setPassword('')
|
||||
setRedirect(true)
|
||||
}else{
|
||||
toast.error("Incorrect email or password");
|
||||
|
|
@ -45,6 +47,7 @@ const LoginForm = ({ setRedirect, hasLabel, layout }) => {
|
|||
<FormGroup>
|
||||
{hasLabel && <Label>Email address</Label>}
|
||||
<Input
|
||||
data-testid="email"
|
||||
placeholder={!hasLabel ? 'Email address' : ''}
|
||||
value={email}
|
||||
onChange={({ target }) => setEmail(target.value)}
|
||||
|
|
@ -54,6 +57,7 @@ const LoginForm = ({ setRedirect, hasLabel, layout }) => {
|
|||
<FormGroup>
|
||||
{hasLabel && <Label>Password</Label>}
|
||||
<Input
|
||||
data-testid="password"
|
||||
placeholder={!hasLabel ? 'Password' : ''}
|
||||
value={password}
|
||||
onChange={({ target }) => setPassword(target.value)}
|
||||
|
|
@ -77,8 +81,8 @@ const LoginForm = ({ setRedirect, hasLabel, layout }) => {
|
|||
</Col>
|
||||
</Row>
|
||||
<FormGroup>
|
||||
<Button color="primary" block className="mt-3" disabled={isDisabled}>
|
||||
Log in
|
||||
<Button color="primary" block className="mt-3" data-testid="submit" disabled={isDisabled}>
|
||||
Sign in
|
||||
</Button>
|
||||
</FormGroup>
|
||||
{/* <Divider className="mt-4">or log in with</Divider>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useContext, useEffect } from 'react';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
import { Switch, Route, Redirect } from 'react-router-dom';
|
||||
import PrivateRoute from '../../helpers/privateRoute';
|
||||
|
||||
import NavbarTop from '../navbar/JKNavbarTop';
|
||||
|
|
@ -16,10 +16,16 @@ import { add as addNotification } from '../../store/features/notificationSlice';
|
|||
|
||||
import { useAuth } from '../../context/UserAuth';
|
||||
|
||||
import Home from './JKHomePage';
|
||||
import HomePage from '../page/JKHomePage';
|
||||
|
||||
import loadable from '@loadable/component';
|
||||
const DashboardRoutes = loadable(() => import('../../layouts/JKDashboardRoutes'));
|
||||
import JKHelp from '../page/JKHelp';
|
||||
import JKPrivacy from '../page/JKPrivacy';
|
||||
import JKPeople from '../page/JKPeople';
|
||||
import JKNotifications from '../page/JKNotifications';
|
||||
|
||||
//import loadable from '@loadable/component';
|
||||
//const DashboardRoutes = loadable(() => import('../../layouts/JKDashboardRoutes'));
|
||||
//const PublicRoutes = loadable(() => import('../../layouts/JKPublicRoutes'))
|
||||
|
||||
function JKDashboard() {
|
||||
const { isFluid, isVertical, navbarStyle } = useContext(AppContext);
|
||||
|
|
@ -28,7 +34,8 @@ function JKDashboard() {
|
|||
const { isAuthenticated, currentUser, setCurrentUser, logout } = useAuth();
|
||||
|
||||
useEffect(() => {
|
||||
DashboardRoutes.preload();
|
||||
//DashboardRoutes.preload();
|
||||
//PublicRoutes.preload();
|
||||
}, []);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
|
@ -124,27 +131,25 @@ function JKDashboard() {
|
|||
useScript(`${process.env.REACT_APP_LEGACY_BASE_URL}/client_scripts`, initJKScripts);
|
||||
|
||||
return (
|
||||
<>
|
||||
{isAuthenticated ? (
|
||||
<div className={isFluid || isKanban ? 'container-fluid' : 'container'}>
|
||||
{isVertical && <NavbarVertical isKanban={isKanban} navbarStyle={navbarStyle} />}
|
||||
<div className={isFluid || isKanban ? 'container-fluid' : 'container'}>
|
||||
{isVertical && <NavbarVertical isKanban={isKanban} navbarStyle={navbarStyle} />}
|
||||
|
||||
<div className="content">
|
||||
<NavbarTop />
|
||||
<Switch>
|
||||
<PrivateRoute path="/" exact component={Home} />
|
||||
<DashboardRoutes />
|
||||
</Switch>
|
||||
{!isKanban && <Footer />}
|
||||
</div>
|
||||
{/* <SidePanelModal path={location.pathname} /> */}
|
||||
</div>
|
||||
) : (
|
||||
<div className="content">
|
||||
<NavbarTop />
|
||||
<Switch>
|
||||
<PrivateRoute path="/" exact component={Home} />
|
||||
<Route path="/" exact component={HomePage} />
|
||||
<Route path="/privacy" component={JKPrivacy} />
|
||||
<Route path="/help" component={JKHelp} />
|
||||
<PrivateRoute path="/friends" component={JKPeople} />
|
||||
<PrivateRoute path="/notifications" component={JKNotifications} />
|
||||
{/*Redirect*/}
|
||||
<Redirect to="/errors/404" />
|
||||
|
||||
</Switch>
|
||||
)}
|
||||
</>
|
||||
{!isKanban && <Footer />}
|
||||
</div>
|
||||
{/* <SidePanelModal path={location.pathname} /> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
import React from 'react';
|
||||
import { Card, CardBody } from 'reactstrap';
|
||||
import FalconCardHeader from '../common/FalconCardHeader';
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const JKHome = () => {
|
||||
const {t} = useTranslation()
|
||||
return (
|
||||
<Card>
|
||||
<FalconCardHeader title={t('page_title', {ns: 'home'})} titleClass="font-weight-semi-bold" />
|
||||
<CardBody className="pt-0">
|
||||
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default JKHome;
|
||||
|
|
@ -1,33 +1,52 @@
|
|||
import React from 'react';
|
||||
import { Col, Row } from 'reactstrap';
|
||||
import { version } from '../../config';
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
const JKFooter = () => {
|
||||
const {t} = useTranslation();
|
||||
|
||||
return (
|
||||
<footer>
|
||||
<Row noGutters className="justify-content-between text-center fs--1 mt-4 mb-3">
|
||||
<Col sm="auto">
|
||||
<p className="mb-0 text-600">
|
||||
Copyright © {new Date().getFullYear()} JamKazam, Inc. All Rights Reserved
|
||||
Copyright © {new Date().getFullYear()} JamKazam, Inc. All Rights Reserved.
|
||||
<span className="ml-2 mb-0 text-600">(v{version})</span>
|
||||
</p>
|
||||
</Col>
|
||||
|
||||
<Col sm="auto">
|
||||
<p className="mb-0 text-600">
|
||||
<p className="mb-0 text-600 text-lowercase">
|
||||
{' '}
|
||||
<a href="https://www.jamkazam.com/corp/about" target="_blank">
|
||||
about
|
||||
<a href={`${process.env.REACT_APP_LEGACY_BASE_URL}/corp/about`} target="_blank">
|
||||
{t('navigation.about', {ns: 'common'})}
|
||||
</a>{' '}
|
||||
|{' '}
|
||||
<a href="https://www.jamkazam.com/corp/privacy" target="_blank">
|
||||
privacy
|
||||
<a href={`${process.env.REACT_APP_LEGACY_BASE_URL}/corp/news`} target="_blank">
|
||||
{t('navigation.news', {ns: 'common'})}
|
||||
</a>{' '}
|
||||
|{' '}
|
||||
<a href="https://www.jamkazam.com/corp/terms" target="_blank">
|
||||
terms of service
|
||||
<a href={`${process.env.REACT_APP_LEGACY_BASE_URL}/corp/media_center`} target="_blank">
|
||||
{t('navigation.media', {ns: 'common'})}
|
||||
</a>{' '}
|
||||
|{' '}
|
||||
<a href={`${process.env.REACT_APP_LEGACY_BASE_URL}/corp/contact`} target="_blank">
|
||||
{t('navigation.contact', {ns: 'common'})}
|
||||
</a>{' '}
|
||||
|{' '}
|
||||
<a href={`${process.env.REACT_APP_LEGACY_BASE_URL}/corp/privacy`} target="_blank">
|
||||
{t('navigation.privacy', {ns: 'common'})}
|
||||
</a>{' '}
|
||||
|{' '}
|
||||
<a href={`${process.env.REACT_APP_LEGACY_BASE_URL}/corp/terms`} target="_blank">
|
||||
{t('navigation.terms', {ns: 'common'})}
|
||||
</a>
|
||||
|{' '}
|
||||
<a href={`${process.env.REACT_APP_LEGACY_BASE_URL}/corp/help`} target="_blank">
|
||||
{t('navigation.help', {ns: 'common'})}
|
||||
</a>
|
||||
</p>
|
||||
{/* <p className="mb-0 text-600">v{version}</p> */}
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
</footer>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
|||
import { useAuth } from '../../context/UserAuth';
|
||||
|
||||
const JKNotificationDropdown = () => {
|
||||
const { currentUser } = useAuth();
|
||||
const { currentUser, isAuthenticated } = useAuth();
|
||||
const dispatch = useDispatch();
|
||||
const notifications = useSelector(state => state.notification.notifications.slice(0, 5));
|
||||
|
||||
|
|
@ -52,6 +52,8 @@ const JKNotificationDropdown = () => {
|
|||
}, [isOpen]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{isAuthenticated &&
|
||||
<Dropdown
|
||||
nav
|
||||
inNavbar
|
||||
|
|
@ -98,6 +100,8 @@ const JKNotificationDropdown = () => {
|
|||
</Card>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ import { useAuth } from '../../context/UserAuth';
|
|||
import JKProfileAvatar from '../profile/JKProfileAvatar';
|
||||
import { useCookies } from 'react-cookie';
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ProfileDropdown = () => {
|
||||
const { t } = useTranslation();
|
||||
const [dropdownOpen, setDropdownOpen] = useState(false);
|
||||
const toggle = () => setDropdownOpen(prevState => !prevState);
|
||||
const { isAuthenticated, currentUser, setCurrentUser, logout } = useAuth();
|
||||
|
|
@ -50,7 +52,7 @@ const ProfileDropdown = () => {
|
|||
{/* <DropdownItem tag={Link} to="/pages/settings">
|
||||
My Profile
|
||||
</DropdownItem> */}
|
||||
<DropdownItem onClick={handleLogout}>Sign out</DropdownItem>
|
||||
<DropdownItem onClick={handleLogout}>{t('signout', { ns: 'auth' })}</DropdownItem>
|
||||
</div>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
|
|
|
|||
|
|
@ -5,45 +5,50 @@ import NotificationDropdown from './JKNotificationDropdown';
|
|||
import LangSwitch from './JKLangSwitch';
|
||||
//import SettingsAnimatedIcon from './SettingsAnimatedIcon';
|
||||
//import CartNotification from './CartNotification';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
//import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { Link } from 'react-router-dom';
|
||||
import AppContext from '../../context/Context';
|
||||
import classNames from 'classnames';
|
||||
import { navbarBreakPoint } from '../../config';
|
||||
//import classNames from 'classnames';
|
||||
//import { navbarBreakPoint } from '../../config';
|
||||
//import { useSelector } from 'react-redux';
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAuth } from '../../context/UserAuth';
|
||||
|
||||
const TopNavRightSideNavItem = () => {
|
||||
|
||||
//const notifications = useSelector(state => state.notification.notifications.slice(0, 5));
|
||||
|
||||
const {t} = useTranslation();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { isTopNav, isCombo } = useContext(AppContext);
|
||||
const { isAuthenticated } = useAuth();
|
||||
|
||||
//const { isTopNav, isCombo } = useContext(AppContext);
|
||||
return (
|
||||
<Nav navbar className="navbar-nav-icons ml-auto flex-row align-items-center">
|
||||
{/* <NavItem>
|
||||
<SettingsAnimatedIcon />
|
||||
</NavItem> */}
|
||||
<NavbarText className="d-none d-md-inline">{t('keep_jamkazam_improving', {ns: 'common'})}:</NavbarText>
|
||||
<NavItem className="d-none d-md-inline ml-1 mr-6">
|
||||
<NavLink>{t('subscribe', {ns: 'common'})}</NavLink>
|
||||
</NavItem>
|
||||
{(isCombo || isTopNav) && (
|
||||
<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" />
|
||||
{!isAuthenticated && (
|
||||
<>
|
||||
<NavbarText className="d-none d-md-inline">{t('keep_jamkazam_improving', { ns: 'common' })}:</NavbarText>
|
||||
<NavItem className="d-none d-md-inline ml-1 mr-6">
|
||||
<a className="nav-link" href={`${process.env.REACT_APP_LEGACY_BASE_URL}/signup`} target="_blank">{t('subscribe', { ns: 'common' })}</a>
|
||||
</NavItem>
|
||||
</>
|
||||
)}
|
||||
|
||||
<LangSwitch />
|
||||
{isAuthenticated ? (
|
||||
<>
|
||||
<NotificationDropdown />
|
||||
<ProfileDropdown />
|
||||
</>
|
||||
) : (
|
||||
<NavItem className="d-none d-md-inline ml-6 mr-2">
|
||||
<NavLink tag={Link} to="/authentication/basic/login">
|
||||
{t('signin', { ns: 'auth' })}
|
||||
</NavLink>
|
||||
<UncontrolledTooltip autohide={false} placement="left" target="changelog">
|
||||
Changelog
|
||||
</UncontrolledTooltip>
|
||||
</NavItem>
|
||||
)}
|
||||
{/* <CartNotification /> */}
|
||||
<LangSwitch />
|
||||
<NotificationDropdown />
|
||||
|
||||
<ProfileDropdown />
|
||||
</Nav>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { NavLink, withRouter } from 'react-router-dom';
|
|||
import { Collapse, Nav, NavItem, NavLink as BootstrapNavLink } from 'reactstrap';
|
||||
import AppContext from '../../context/Context';
|
||||
import NavbarVerticalMenuItem from './NavbarVerticalMenuItem';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
const NavbarVerticalMenu = ({ routes, location }) => {
|
||||
const [openedIndex, setOpenedIndex] = useState(null);
|
||||
|
|
@ -66,7 +67,7 @@ const NavbarVerticalMenu = ({ routes, location }) => {
|
|||
</NavItem>
|
||||
</Fragment>
|
||||
);
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
NavbarVerticalMenu.propTypes = {
|
||||
|
|
|
|||
|
|
@ -12,34 +12,34 @@ import { fetchPeople } from '../../store/features/peopleSlice';
|
|||
import JKPeopleSearch from './JKPeopleSearch';
|
||||
import JKPeopleList from './JKPeopleList';
|
||||
import JKPeopleSwiper from './JKPeopleSwiper';
|
||||
import { useResponsive } from '@farfetch/react-context-responsive';
|
||||
|
||||
const JKPeople = ({ className }) => {
|
||||
const [showSearch, setShowSearch] = useState(false);
|
||||
const [page, setPage] = useState(1);
|
||||
const [resetFilter, setResetFilter] = useState(false)
|
||||
const [resetFilter, setResetFilter] = useState(false);
|
||||
const peopleListRef = useRef();
|
||||
const dispatch = useDispatch();
|
||||
const {t} = useTranslation();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const people = useSelector(state => state.people.people);
|
||||
const totalPages = useSelector(state => state.people.totalPages);
|
||||
const loadingStatus = useSelector(state => state.people.status);
|
||||
|
||||
const loadPeople = React.useCallback(
|
||||
() => {
|
||||
if(totalPages !== 0 && page > totalPages){
|
||||
setPage(totalPages + 1);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
console.log('BEFORE fetching people');
|
||||
dispatch(fetchPeople({ page }));
|
||||
} catch (error) {
|
||||
console.log('Error fetching people', error);
|
||||
}
|
||||
},
|
||||
[page, totalPages, dispatch]
|
||||
);
|
||||
const { greaterThan } = useResponsive();
|
||||
|
||||
const loadPeople = React.useCallback(() => {
|
||||
if (totalPages !== 0 && page > totalPages) {
|
||||
setPage(totalPages + 1);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
console.log('BEFORE fetching people');
|
||||
dispatch(fetchPeople({ page }));
|
||||
} catch (error) {
|
||||
console.log('Error fetching people', error);
|
||||
}
|
||||
}, [page, totalPages, dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
loadPeople();
|
||||
|
|
@ -66,8 +66,6 @@ const JKPeople = ({ className }) => {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('scroll', handleScroll, { passive: true });
|
||||
return () => {
|
||||
|
|
@ -77,17 +75,30 @@ const JKPeople = ({ className }) => {
|
|||
|
||||
return (
|
||||
<Card>
|
||||
<JKPeopleSearch show={showSearch} setShow={setShowSearch} resetFilter={resetFilter} setResetFilter={setResetFilter} />
|
||||
<FalconCardHeader
|
||||
title={t('page_title', {ns: 'people'})}
|
||||
titleClass="font-weight-bold"
|
||||
>
|
||||
<JKPeopleSearch
|
||||
show={showSearch}
|
||||
setShow={setShowSearch}
|
||||
resetFilter={resetFilter}
|
||||
setResetFilter={setResetFilter}
|
||||
/>
|
||||
<FalconCardHeader title={t('page_title', { ns: 'people' })} titleClass="font-weight-bold">
|
||||
<Form inline className="mt-md-0 mt-3">
|
||||
<Button color="primary" className="me-2 mr-2 fs--1" onClick={() => setShowSearch(!showSearch)} data-testid="btnUpdateSearch">
|
||||
{t('update_search', {ns: 'people'})}
|
||||
<Button
|
||||
color="primary"
|
||||
className="me-2 mr-2 fs--1"
|
||||
onClick={() => setShowSearch(!showSearch)}
|
||||
data-testid="btnUpdateSearch"
|
||||
>
|
||||
{t('update_search', { ns: 'people' })}
|
||||
</Button>
|
||||
<Button outline color="secondary" className="fs--1" data-testid="btnResetSearch" onClick={() => setResetFilter(true)}>
|
||||
{t('reset_filters', {ns: 'people'})}
|
||||
<Button
|
||||
outline
|
||||
color="secondary"
|
||||
className="fs--1"
|
||||
data-testid="btnResetSearch"
|
||||
onClick={() => setResetFilter(true)}
|
||||
>
|
||||
{t('reset_filters', { ns: 'people' })}
|
||||
</Button>
|
||||
</Form>
|
||||
</FalconCardHeader>
|
||||
|
|
@ -98,18 +109,18 @@ const JKPeople = ({ className }) => {
|
|||
) : isIterableArray(people) ? (
|
||||
//Start Find Friends table hidden on small screens
|
||||
<>
|
||||
<Row className="mb-3 justify-content-between d-none d-md-block">
|
||||
<div className="table-responsive-xl px-2" ref={peopleListRef}>
|
||||
<JKPeopleList people={people} />
|
||||
{
|
||||
loadingStatus === 'loading' && people.length !== 0 &&
|
||||
<span>loading...</span>
|
||||
}
|
||||
</div>
|
||||
</Row>
|
||||
<Row className="swiper-container d-block d-md-none">
|
||||
<JKPeopleSwiper people={people} goNextPage={goNextPage} />
|
||||
</Row>
|
||||
{greaterThan.xs ? (
|
||||
<Row className="mb-3 justify-content-between d-none d-md-block">
|
||||
<div className="table-responsive-xl px-2" ref={peopleListRef}>
|
||||
<JKPeopleList people={people} />
|
||||
{loadingStatus === 'loading' && people.length !== 0 && <span>loading...</span>}
|
||||
</div>
|
||||
</Row>
|
||||
) : (
|
||||
<Row className="swiper-container d-block d-md-none" data-testid="peopleSwiper">
|
||||
<JKPeopleSwiper people={people} goNextPage={goNextPage} />
|
||||
</Row>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Row className="p-card">
|
||||
|
|
|
|||
|
|
@ -2,43 +2,32 @@ import React from 'react';
|
|||
import { Table } from 'reactstrap';
|
||||
import JKPerson from './JKPerson';
|
||||
import PropTypes from 'prop-types';
|
||||
import {useTranslation} from 'react-i18next'
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const JKPeopleList = ({ people }) => {
|
||||
const {t} = useTranslation()
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
<Table striped bordered className="fs--1" data-testid="peopleListTable">
|
||||
<thead className="bg-200 text-900">
|
||||
<tr>
|
||||
<th scope="col">{t('person_attributes.name', {ns: 'people'})}</th>
|
||||
<th scope="col" style={{ minWidth: 250 }}>
|
||||
{t('person_attributes.about', {ns: 'people'})}
|
||||
</th>
|
||||
<th scope="col">{t('person_attributes.instruments', {ns: 'people'})}</th>
|
||||
|
||||
<th scope="col">{t('actions', {ns: 'common'})}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="list">
|
||||
{people.map((person, index) => (
|
||||
<tr className="align-middle" key={`people-list-item-${person.id}`}>
|
||||
<JKPerson person={person} viewMode="list" />
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</Table>
|
||||
<Table striped bordered className="fs--1" data-testid="peopleListTable">
|
||||
<thead className="bg-200 text-900">
|
||||
<tr>
|
||||
<th scope="col">{t('person_attributes.name', { ns: 'people' })}</th>
|
||||
<th scope="col" style={{ minWidth: 250 }}>
|
||||
{t('person_attributes.about', { ns: 'people' })}
|
||||
</th>
|
||||
<th scope="col">{t('person_attributes.instruments', { ns: 'people' })}</th>
|
||||
<th scope="col">{t('person_attributes.genres', { ns: 'people' })}</th>
|
||||
<th scope="col">{t('actions', { ns: 'common' })}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="list">
|
||||
{people.map((person) => (
|
||||
// <tr className="align-middle" key={`people-list-item-${person.id}`}>
|
||||
<JKPerson person={person} viewMode="list" key={`jk-person-${person.id}`} />
|
||||
// </tr>
|
||||
))}
|
||||
</tbody>
|
||||
</Table>
|
||||
|
||||
{/* <Row>
|
||||
<Col>
|
||||
{page < totalPages && (
|
||||
<a className="ml-2 fw-semi-bold" href="#!" onClick={goNextPage}>
|
||||
More...
|
||||
</a>
|
||||
)}
|
||||
</Col>
|
||||
</Row> */}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ const JKPeopleSearch = props => {
|
|||
defaultValues: {
|
||||
latency_good: true,
|
||||
latency_fair: true,
|
||||
latency_high: true,
|
||||
latency_high: false,
|
||||
proficiency_beginner: true,
|
||||
proficiency_intermediate: true,
|
||||
proficiency_expert: true,
|
||||
|
|
@ -117,18 +117,18 @@ const JKPeopleSearch = props => {
|
|||
|
||||
const lastActiveOpts = [
|
||||
{ value: '', label: 'Any Range' },
|
||||
{ value: '1', label: 'Within Last 1 Day' },
|
||||
{ value: '7', label: 'Within Last 7 Day' },
|
||||
{ value: '30', label: 'Within Last 30 Day' },
|
||||
{ value: '90', label: 'Within Last 90 Day' }
|
||||
{ value: '1', label: 'Within Last 1 Days' },
|
||||
{ value: '7', label: 'Within Last 7 Days' },
|
||||
{ value: '30', label: 'Within Last 30 Days' },
|
||||
{ value: '90', label: 'Within Last 90 Days' }
|
||||
];
|
||||
|
||||
const joinedOpts = [
|
||||
{ value: '', label: 'Any Range' },
|
||||
{ value: '1', label: 'Within Last 1 Day' },
|
||||
{ value: '7', label: 'Within Last 7 Day' },
|
||||
{ value: '30', label: 'Within Last 30 Day' },
|
||||
{ value: '90', label: 'Within Last 90 Day' }
|
||||
{ value: '1', label: 'Within Last 1 Days' },
|
||||
{ value: '7', label: 'Within Last 7 Days' },
|
||||
{ value: '30', label: 'Within Last 30 Days' },
|
||||
{ value: '90', label: 'Within Last 90 Days' }
|
||||
];
|
||||
|
||||
return (
|
||||
|
|
@ -145,7 +145,7 @@ const JKPeopleSearch = props => {
|
|||
<div className="col-6">
|
||||
<label className="form-label">
|
||||
Latency{' '}
|
||||
<JKTooltip title="Latency is the round-trip travel time over the Internet between you and your friend in a session. JamKazam works best with the lowest latency, measured in milliseconds (ms)" />
|
||||
<JKTooltip title="Use these checkboxes to search for other musicians by the estimated amount of latency between you and them. Latency is the amount of time it takes for each of your computers to process audio, plus the time it takes for this digital audio to move over the Internet between you." />
|
||||
</label>
|
||||
<div className="form-check">
|
||||
<input
|
||||
|
|
@ -155,7 +155,7 @@ const JKPeopleSearch = props => {
|
|||
defaultChecked={!isDirty}
|
||||
onChange={e => setValue('latency_good', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">Good (40ms or less)</label>
|
||||
<label className="form-check-label">Good (less than 40ms)</label>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input
|
||||
|
|
@ -165,23 +165,23 @@ const JKPeopleSearch = props => {
|
|||
defaultChecked={!isDirty}
|
||||
onChange={e => setValue('latency_fair', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">Fair (41-80ms)</label>
|
||||
<label className="form-check-label">Fair (40-60ms)</label>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input
|
||||
{...register('latency_high')}
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
defaultChecked={!isDirty}
|
||||
defaultChecked={isDirty}
|
||||
onChange={e => setValue('latency_high', e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label">High (81ms +)</label>
|
||||
<label className="form-check-label">Poor (more than 60ms)</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-6">
|
||||
<label className="form-label">
|
||||
Skill Level <JKTooltip title="Select the skill levels you want to filter for." />
|
||||
Skill Level <JKTooltip title="Use these checkboxes to search for other musicians by their skill level." />
|
||||
</label>
|
||||
<div className="form-check">
|
||||
<input
|
||||
|
|
@ -221,7 +221,7 @@ const JKPeopleSearch = props => {
|
|||
<div className="col-12 col-md-6">
|
||||
<label className="form-label" htmlFor="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="Use these checkboxes to search for other musicians who play particular instruments. If you do not select any instruments, we search for any/all instruments. If you select multiple instruments, we search for musicians who play any of these instruments." />
|
||||
</label>
|
||||
<div className="choices">
|
||||
<Controller
|
||||
|
|
@ -234,7 +234,7 @@ const JKPeopleSearch = props => {
|
|||
</div>
|
||||
<label className="form-label" htmlFor="genres">
|
||||
Genres{' '}
|
||||
<JKTooltip title="Select one or more genres to filter for. If this field is blank, all genres will be included." />
|
||||
<JKTooltip title="Use these checkboxes to search for other musicians who enjoy playing particular musical genres/styles. If you do not select any genres, we search for any/all genres. If you select multiple genres, we search for musicians who play any of these genres." />
|
||||
</label>
|
||||
<div className="choices">
|
||||
<Controller
|
||||
|
|
@ -246,7 +246,7 @@ const JKPeopleSearch = props => {
|
|||
/>
|
||||
</div>
|
||||
<label className="form-label" htmlFor="lastActive">
|
||||
Last Active <JKTooltip title="Select onefor when the user was last active on JamKazam." />
|
||||
Last Active <JKTooltip title="Use this list to search for other musicians who have been active on JamKazam within a specified time period. More recent activity makes it more likely they will respond if you message or request to connect." />
|
||||
</label>
|
||||
<div className="choices">
|
||||
<Controller
|
||||
|
|
@ -258,7 +258,7 @@ const JKPeopleSearch = props => {
|
|||
/>
|
||||
</div>
|
||||
<label className="form-label" htmlFor="joined">
|
||||
Joined JamKazam <JKTooltip title="Select onefor when the user joined JamKazam." />
|
||||
Joined JamKazam <JKTooltip title="Use this list to search for other musicians based on when they joined JamKazam. This can be useful for finding and connecting with newer users." />
|
||||
</label>
|
||||
<div className="choices">
|
||||
<Controller
|
||||
|
|
|
|||
|
|
@ -4,42 +4,44 @@ import { Row, Col } from 'reactstrap';
|
|||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { useAuth } from '../../context/UserAuth';
|
||||
import { truncate } from '../../helpers/utils';
|
||||
import { fetchPerson } from '../../store/features/peopleSlice'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { fetchPerson } from '../../store/features/peopleSlice';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useResponsive } from '@farfetch/react-context-responsive';
|
||||
|
||||
import JKProfileSidePanel from '../profile/JKProfileSidePanel';
|
||||
import JKProfileAvatar from '../profile/JKProfileAvatar';
|
||||
import JKProfileInstrumentsList from '../profile/JKProfileInstrumentsList';
|
||||
import JKProfileGenres from '../profile/JKProfileGenres';
|
||||
import JKConnectButton from '../profile/JKConnectButton';
|
||||
import JKMessageButton from '../profile/JKMessageButton';
|
||||
import JKLatencyBadge from '../profile/JKLatencyBadge';
|
||||
import JKLastActiveAgo from '../profile/JKLastActiveAgo';
|
||||
|
||||
const JKPerson = props => {
|
||||
const { id, name, biography, photo_url, instruments, latency_data, last_active_timestamp } = props.person;
|
||||
const viewMode = props.viewMode;
|
||||
const { id, name, biography, photo_url, instruments, genres, latency_data, last_active_timestamp } = props.person;
|
||||
const { currentUser } = useAuth();
|
||||
const [showSidePanel, setShowSidePanel] = useState(false);
|
||||
const dispatch = useDispatch()
|
||||
const {t} = useTranslation()
|
||||
const user = useSelector(state => state.people.people.find(p => p.id === id))
|
||||
const dispatch = useDispatch();
|
||||
const { t } = useTranslation();
|
||||
const user = useSelector(state => state.people.people.find(p => p.id === id));
|
||||
const { greaterThan } = useResponsive()
|
||||
|
||||
const toggleMoreDetails = async (e) => {
|
||||
const toggleMoreDetails = async e => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
await dispatch(fetchPerson({userId: id})).unwrap()
|
||||
await dispatch(fetchPerson({ userId: id })).unwrap();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
|
||||
setShowSidePanel(prev => !prev);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{viewMode === 'list' ? (
|
||||
<>
|
||||
{greaterThan.xs ? (
|
||||
<tr className="align-middle" key={`people-list-item-${id}`}>
|
||||
<td className="text-nowrap">
|
||||
<a href="/#" onClick={toggleMoreDetails} className="d-flex align-items-center mb-1 fs-0">
|
||||
<div className="avatar avatar-xl">
|
||||
|
|
@ -50,25 +52,28 @@ const JKPerson = props => {
|
|||
</div>
|
||||
</a>
|
||||
<div>
|
||||
<strong>{t('person_attributes.latency_to_me', {ns: 'people'})}:</strong>
|
||||
<strong>{t('person_attributes.latency_to_me', { ns: 'people' })}:</strong>
|
||||
<JKLatencyBadge latencyData={latency_data} />
|
||||
</div>
|
||||
<div>
|
||||
<strong>{t('person_attributes.last_active', {ns: 'people'})}:</strong> <JKLastActiveAgo timestamp={last_active_timestamp} />
|
||||
<strong>{t('person_attributes.last_active', { ns: 'people' })}:</strong>{' '}
|
||||
<JKLastActiveAgo timestamp={last_active_timestamp} />
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{truncate(biography, 200)}
|
||||
<td data-testid="biography-col">
|
||||
{truncate(biography, 310)}
|
||||
{biography && biography.length > 200 && (
|
||||
<a href="/#" data-testid="linkMore" onClick={toggleMoreDetails}>
|
||||
{' '} {t('more', {ns: 'common'})} »
|
||||
{' '} {t('more', { ns: 'common' })} »
|
||||
</a>
|
||||
)}
|
||||
</td>
|
||||
<td>
|
||||
<JKProfileInstrumentsList instruments={instruments} />
|
||||
<td data-testid="instruments-col">
|
||||
<JKProfileInstrumentsList instruments={instruments} toggleMoreDetails={toggleMoreDetails} />
|
||||
</td>
|
||||
<td data-testid="genres-col">
|
||||
<JKProfileGenres genres={genres} toggleMoreDetails={toggleMoreDetails} />
|
||||
</td>
|
||||
|
||||
<td className="text-nowrap">
|
||||
<JKConnectButton
|
||||
currentUser={currentUser}
|
||||
|
|
@ -83,34 +88,50 @@ const JKPerson = props => {
|
|||
</JKMessageButton>
|
||||
|
||||
<a href="/#" onClick={toggleMoreDetails} data-testid="btnMore">
|
||||
<span className="btn btn-primary fs--1 px-2 py-1" data-bs-toggle="tooltip" title={t('view_profile', {ns: 'people'})}>
|
||||
<span
|
||||
className="btn btn-primary fs--1 px-2 py-1"
|
||||
data-bs-toggle="tooltip"
|
||||
title={t('view_profile', { ns: 'people' })}
|
||||
>
|
||||
<FontAwesomeIcon icon="user" transform="shrink-4 down-1" className="mr-1" />
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
</>
|
||||
</tr>
|
||||
) : (
|
||||
<>
|
||||
<Row>
|
||||
<Col>
|
||||
<div>
|
||||
<strong>{t('person_attributes.latency_to_me', {ns: 'people'})}:</strong> <JKLatencyBadge latencyData={latency_data} />
|
||||
<strong>{t('person_attributes.latency_to_me', { ns: 'people' })}:</strong>{' '}
|
||||
<JKLatencyBadge latencyData={latency_data} />
|
||||
</div>
|
||||
<div>
|
||||
<strong>{t('person_attributes.last_active', {ns: 'people'})}:</strong> <JKLastActiveAgo timestamp={last_active_timestamp} />
|
||||
<strong>{t('person_attributes.last_active', { ns: 'people' })}:</strong>{' '}
|
||||
<JKLastActiveAgo timestamp={last_active_timestamp} />
|
||||
</div>
|
||||
</Col>
|
||||
<Col className="d-none d-sm-block">
|
||||
<h5>{t('person_attributes.instruments', {ns: 'people'})}</h5>
|
||||
<JKProfileInstrumentsList instruments={instruments} />
|
||||
<h5>{t('person_attributes.instruments', { ns: 'people' })}</h5>
|
||||
<JKProfileInstrumentsList instruments={instruments} toggleMoreDetails={toggleMoreDetails} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="d-block d-sm-none mt-3">
|
||||
<Col>
|
||||
<h5>{t('person_attributes.instruments', {ns: 'people'})}</h5>
|
||||
<JKProfileInstrumentsList instruments={instruments} />
|
||||
<h5>{t('person_attributes.instruments', { ns: 'people' })}</h5>
|
||||
<JKProfileInstrumentsList instruments={instruments} toggleMoreDetails={toggleMoreDetails} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="d-block d-sm-none mt-3">
|
||||
<Col>
|
||||
<h5>{t('person_attributes.genres', { ns: 'people' })}</h5>
|
||||
<JKProfileGenres genres={genres} toggleMoreDetails={toggleMoreDetails} />
|
||||
</Col>
|
||||
</Row>
|
||||
<br />
|
||||
<Row data-testid="mobBiography">
|
||||
<Col>{biography}</Col>
|
||||
</Row>
|
||||
<br />
|
||||
|
||||
<JKConnectButton
|
||||
|
|
@ -126,7 +147,11 @@ const JKPerson = props => {
|
|||
</JKMessageButton>
|
||||
|
||||
<a href="/#" onClick={toggleMoreDetails} data-testid="btnMore">
|
||||
<span className="btn btn-primary fs--1 px-2 py-1" data-bs-toggle="tooltip" title={t('view_profile', {ns: 'people'})}>
|
||||
<span
|
||||
className="btn btn-primary fs--1 px-2 py-1"
|
||||
data-bs-toggle="tooltip"
|
||||
title={t('view_profile', { ns: 'people' })}
|
||||
>
|
||||
<FontAwesomeIcon icon="user" transform="shrink-4 down-1" className="mr-1" />
|
||||
</span>
|
||||
</a>
|
||||
|
|
@ -138,8 +163,7 @@ const JKPerson = props => {
|
|||
};
|
||||
|
||||
JKPerson.propTypes = {
|
||||
person: PropTypes.object.isRequired,
|
||||
viewMode: PropTypes.string
|
||||
person: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default JKPerson;
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ const JKConnectButton = props => {
|
|||
)
|
||||
.then(resp => {
|
||||
if (resp.ok && resp.status === 201) {
|
||||
toast.success('Friend request was sent successfully');
|
||||
toast.success(`Success! Your friend request has been sent to ${user.name}.`);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
toast.error('An error encountered when sending friend request');
|
||||
toast.error('An error encountered when sending friend request.');
|
||||
setPendingFriendRequest(false);
|
||||
});
|
||||
};
|
||||
|
|
@ -70,17 +70,17 @@ const JKConnectButton = props => {
|
|||
className={`btn btn-primary ${cssClasses}`}
|
||||
data-testid="connect"
|
||||
disabled={pendingFriendRequest}
|
||||
onClick={confirm}
|
||||
onClick={addFriend}
|
||||
title={buttonTitle()}
|
||||
>
|
||||
{addContent}
|
||||
</button>
|
||||
<ConnectConfirmModal
|
||||
{/* <ConnectConfirmModal
|
||||
show={showConfirmModal}
|
||||
setShow={setShowConfirmModal}
|
||||
user={user}
|
||||
handleOnConfirm={addFriend}
|
||||
/>
|
||||
/> */}
|
||||
</>
|
||||
) : (
|
||||
<button
|
||||
|
|
@ -103,33 +103,33 @@ JKConnectButton.propTypes = {
|
|||
removeContent: PropTypes.element.isRequired
|
||||
};
|
||||
|
||||
const ConnectConfirmModal = props => {
|
||||
const { className, show, setShow, user, handleOnConfirm } = props;
|
||||
// const ConnectConfirmModal = props => {
|
||||
// const { className, show, setShow, user, handleOnConfirm } = props;
|
||||
|
||||
//const [modal, setModal] = useState(show);
|
||||
// //const [modal, setModal] = useState(show);
|
||||
|
||||
const toggle = () => setShow(!show);
|
||||
// const toggle = () => setShow(!show);
|
||||
|
||||
const accept = () => {
|
||||
handleOnConfirm();
|
||||
};
|
||||
// const accept = () => {
|
||||
// handleOnConfirm();
|
||||
// };
|
||||
|
||||
return (
|
||||
// return (
|
||||
|
||||
<Modal isOpen={show} toggle={toggle} className={className} centered={true} data-testid="confirmFriendRequestModal">
|
||||
<ModalHeader toggle={toggle}>Send Friend Request</ModalHeader>
|
||||
<ModalBody>Send a friend request to {user.name}.</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="primary" onClick={accept}>
|
||||
Yes
|
||||
</Button>{' '}
|
||||
<Button color="secondary" onClick={toggle}>
|
||||
No
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
// <Modal isOpen={show} toggle={toggle} className={className} centered={true} data-testid="confirmFriendRequestModal">
|
||||
// <ModalHeader toggle={toggle}>Send Friend Request</ModalHeader>
|
||||
// <ModalBody>Send a friend request to {user.name}.</ModalBody>
|
||||
// <ModalFooter>
|
||||
// <Button color="primary" onClick={accept}>
|
||||
// Yes
|
||||
// </Button>{' '}
|
||||
// <Button color="secondary" onClick={toggle}>
|
||||
// No
|
||||
// </Button>
|
||||
// </ModalFooter>
|
||||
// </Modal>
|
||||
|
||||
);
|
||||
};
|
||||
// );
|
||||
// };
|
||||
|
||||
export default JKConnectButton;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ const JKLatencyBadge = ({ latencyData, showAll }) => {
|
|||
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 },
|
||||
me: { label: 'ME', min: -1, max: -1 },
|
||||
unknown: { label: 'UNKNOWN', min: -2, max: -2 }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,36 @@
|
|||
import React from "react";
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useResponsive } from '@farfetch/react-context-responsive';
|
||||
|
||||
const JKProfileGenres = ({genres}) => {
|
||||
let items = []
|
||||
|
||||
const getGenresNames = () => {
|
||||
for(let genre of genres){
|
||||
items.push(genre.genre_id)
|
||||
}
|
||||
return items.join(', ');
|
||||
}
|
||||
|
||||
return (
|
||||
<div>{getGenresNames()}</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default JKProfileGenres;
|
||||
const JKProfileGenres = ({ genres, showAll, toggleMoreDetails }) => {
|
||||
const LIMIT = 4;
|
||||
const [genresToShow, setGenresToShow] = useState([]);
|
||||
const { greaterThan } = useResponsive();
|
||||
|
||||
useEffect(() => {
|
||||
showAll || !greaterThan.xs ? setGenresToShow(genres) : setGenresToShow(genres.slice(0, LIMIT));
|
||||
}, [showAll]);
|
||||
|
||||
return (
|
||||
<div data-testid="genreList">
|
||||
{ genresToShow && <div className="text-capitalize">{genresToShow.map(g => g.description ? g.description : g.genre_id).join(', ')}</div>}
|
||||
{((!showAll && greaterThan.xs) || (showAll && !greaterThan.xs)) && genres.length > LIMIT && (
|
||||
<a href="#/" onClick={e => toggleMoreDetails(e)}>
|
||||
More »
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
JKProfileGenres.propTypes = {
|
||||
genres: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
showAll: PropTypes.bool,
|
||||
toggleMoreDetails: PropTypes.func
|
||||
};
|
||||
|
||||
JKProfileGenres.defaltProps = {
|
||||
showAll: false
|
||||
};
|
||||
|
||||
export default JKProfileGenres;
|
||||
|
|
|
|||
|
|
@ -1,24 +1,50 @@
|
|||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useResponsive, useIsMobile } from '@farfetch/react-context-responsive';
|
||||
|
||||
const JKPersonInstrumentsList = ({ instruments }) => {
|
||||
const JKPersonInstrumentsList = ({ instruments, showAll, toggleMoreDetails }) => {
|
||||
const proficiencies = {
|
||||
'1': 'Beginner',
|
||||
'2': 'Intermediate',
|
||||
'3': 'Expert'
|
||||
};
|
||||
|
||||
const LIMIT = 4;
|
||||
|
||||
const [instrumentsToShow, setInstrumentsToShow] = useState([]);
|
||||
|
||||
const { greaterThan } = useResponsive();
|
||||
const { isMobile } = useIsMobile();
|
||||
|
||||
useEffect(() => {
|
||||
showAll || !greaterThan.xs ? setInstrumentsToShow(instruments) : setInstrumentsToShow(instruments.slice(0, LIMIT));
|
||||
}, [showAll]);
|
||||
|
||||
return (
|
||||
instruments &&
|
||||
instruments.map(instrument => (
|
||||
<div key={instrument.instrument_id} className="text-nowrap">
|
||||
<strong>{instrument.description}:</strong> {proficiencies[instrument.proficiency_level]}
|
||||
</div>
|
||||
))
|
||||
<div data-testid="instrumentList">
|
||||
{instrumentsToShow &&
|
||||
instrumentsToShow.map(instrument => (
|
||||
<div key={instrument.instrument_id} className="text-nowrap">
|
||||
<strong>{instrument.description}:</strong> {proficiencies[instrument.proficiency_level]}
|
||||
</div>
|
||||
))}
|
||||
{((!showAll && greaterThan.xs) || (showAll && !greaterThan.xs)) && instruments.length > LIMIT && (
|
||||
<a href="#/" onClick={e => toggleMoreDetails(e)}>
|
||||
More »
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
JKPersonInstrumentsList.propTypes = {
|
||||
instruments: PropTypes.arrayOf(PropTypes.object)
|
||||
}
|
||||
instruments: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
showAll: PropTypes.bool,
|
||||
toggleMoreDetails: PropTypes.func
|
||||
};
|
||||
|
||||
export default JKPersonInstrumentsList
|
||||
JKPersonInstrumentsList.defaltProps = {
|
||||
showAll: false
|
||||
};
|
||||
|
||||
export default JKPersonInstrumentsList;
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ const JKProfileSidePanel = props => {
|
|||
{user.instruments && user.instruments.length && (
|
||||
<div data-testid="instruments">
|
||||
<h5>{t('person_attributes.instruments', {ns: 'people'})}</h5>
|
||||
<JKProfileInstrumentsList instruments={user.instruments} />
|
||||
<JKProfileInstrumentsList instruments={user.instruments} showAll={true} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ const JKProfileSidePanel = props => {
|
|||
<div data-testid="genres">
|
||||
<br />
|
||||
<h5>{t('person_attributes.genres', {ns: 'people'})}</h5>
|
||||
<JKProfileGenres genres={user.genres} />
|
||||
<JKProfileGenres genres={user.genres} showAll={true} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"signup": "Sign up",
|
||||
"signin": "Sign in"
|
||||
"signup": "Sign Up",
|
||||
"signin": "Sign In",
|
||||
"signout": "Sign Out"
|
||||
}
|
||||
|
|
@ -7,6 +7,12 @@
|
|||
"navigation": {
|
||||
"home": "Home",
|
||||
"friends": "Friends",
|
||||
"help": "Help"
|
||||
"help": "Help",
|
||||
"about": "About",
|
||||
"news": "News",
|
||||
"media": "Media",
|
||||
"contact": "Contact",
|
||||
"privacy": "Privacy",
|
||||
"terms": "Terms of Service"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"page_title": "Home page"
|
||||
"page_title": "Home"
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
"update_search": "Update Search",
|
||||
"reset_filters": "Reset Filters",
|
||||
"view_profile": "View profile",
|
||||
"add_friend": "Add Friends",
|
||||
"add_friend": "Send Friend Request",
|
||||
"disconnect": "Disconnect",
|
||||
"send_message": "Send Message",
|
||||
"person_attributes": {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"signup": "Sign up",
|
||||
"signin": "Sign in"
|
||||
"signup": "Sign Up",
|
||||
"signin": "Sign In",
|
||||
"signout": "Sign Out"
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ const AuthBasicLayout = ({location}) => (
|
|||
<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 width="200"/>
|
||||
<Logo width={200} />
|
||||
<Card>
|
||||
<CardBody className="fs--1 font-weight-normal p-5">
|
||||
<UserAuth path={location.pathname}>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
//import DashboardLoadingIndicator from '../components/dashboard/JKDashboardLoadingIndicator';
|
||||
import Dashboard from '../components/dashboard/JKDashboardMain';
|
||||
import DashboardMain from '../components/dashboard/JKDashboardMain';
|
||||
import UserAuth from '../context/UserAuth';
|
||||
|
||||
const DashboardLayout = ({ location }) => {
|
||||
|
|
@ -12,7 +11,7 @@ const DashboardLayout = ({ location }) => {
|
|||
|
||||
return (
|
||||
<UserAuth path={location.pathname}>
|
||||
<Dashboard />
|
||||
<DashboardMain />
|
||||
</UserAuth>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export const helpRoute = {
|
|||
name: 'Help',
|
||||
to: '/help',
|
||||
exact: true,
|
||||
icon: 'search',
|
||||
icon: 'question-circle'
|
||||
}
|
||||
|
||||
export const legacyRoute = {
|
||||
|
|
|
|||
|
|
@ -77,6 +77,10 @@ if @search.is_a?(BaseSearch)
|
|||
[musician.updated_at, musician.last_jam_updated_at].compact.max.to_i
|
||||
end
|
||||
end
|
||||
|
||||
child :genres => :genres do
|
||||
attributes :genre_id, :description
|
||||
end
|
||||
}
|
||||
|
||||
elsif @search.is_a?(BandSearch)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ child :performance_samples => :performance_samples do
|
|||
end
|
||||
|
||||
child :genre_players => :genres do
|
||||
attributes :genre_id, :player_type, :genre_type
|
||||
attributes :genre_id, :player_type, :genre_type, :description
|
||||
end
|
||||
|
||||
child :band_musicians => :bands do
|
||||
|
|
|
|||
Loading…
Reference in New Issue