From 7cf5648b7868b0f7fb59ea6ad6a6c26a9fa72613 Mon Sep 17 00:00:00 2001 From: Nuwan Date: Mon, 12 Aug 2024 11:48:04 +0530 Subject: [PATCH] jamtrack player, cusmtom mixes and download mixes --- .../e2e/jamtracks/jamtracks-page.cy.js | 2 +- .../e2e/jamtracks/my-jamtracks-page.cy.js | 41 ++ .../cypress/fixtures/my_jamtracks_page1.json | 562 ++++++++++++++++++ .../components/jamtracks/JKCreateCustomMix.js | 104 ++-- jam-ui/src/components/jamtracks/JKJamTrack.js | 82 +-- .../components/jamtracks/JKJamTrackPlayer.js | 19 +- .../components/jamtracks/JKMyJamTrackMixes.js | 104 +++- .../src/components/jamtracks/JKMyJamTracks.js | 71 +-- jam-ui/src/helpers/initFA.js | 12 +- jam-ui/src/helpers/rest.js | 15 +- jam-ui/src/store/features/jamTrackSlice.js | 101 ++++ jam-ui/src/store/features/myJamTracksSlice.js | 63 ++ jam-ui/src/store/store.js | 4 + 13 files changed, 1014 insertions(+), 166 deletions(-) create mode 100644 jam-ui/cypress/e2e/jamtracks/my-jamtracks-page.cy.js create mode 100644 jam-ui/cypress/fixtures/my_jamtracks_page1.json create mode 100644 jam-ui/src/store/features/jamTrackSlice.js create mode 100644 jam-ui/src/store/features/myJamTracksSlice.js diff --git a/jam-ui/cypress/e2e/jamtracks/jamtracks-page.cy.js b/jam-ui/cypress/e2e/jamtracks/jamtracks-page.cy.js index 8cd1360cc..83b7600f0 100644 --- a/jam-ui/cypress/e2e/jamtracks/jamtracks-page.cy.js +++ b/jam-ui/cypress/e2e/jamtracks/jamtracks-page.cy.js @@ -23,7 +23,7 @@ describe('JamTracks Page', () => { cy.get('input[type="search"]').should('exist'); }); - describe('search artists', () => { + describe('search', () => { beforeEach(() => { //http://www.jamkazam.local:3000/api/jamtracks/autocomplete?match=ac+&limit=5 // cy.intercept('GET', /S+\/jamtracks\/autocomplete\?match=ac\S+/, { diff --git a/jam-ui/cypress/e2e/jamtracks/my-jamtracks-page.cy.js b/jam-ui/cypress/e2e/jamtracks/my-jamtracks-page.cy.js new file mode 100644 index 000000000..efa950eb5 --- /dev/null +++ b/jam-ui/cypress/e2e/jamtracks/my-jamtracks-page.cy.js @@ -0,0 +1,41 @@ +/// + +import makeFakeUser from '../../factories/user'; + +describe('JamTracks Page', () => { + beforeEach(() => { + const currentUser = makeFakeUser(); + cy.stubAuthenticate({ id: currentUser.id }); + cy.visit('/my-jamtracks'); + }); + + it('should display the My JamTracks page', () => { + cy.get('.card-header h5').should('contain', 'My JamTracks'); + }); + + it('should display the search bar', () => { + cy.get('input[type="search"]').should('exist'); + }); + + describe('filter', () => { + beforeEach(() => { + cy.intercept('GET', /\S+\/jamtracks\/purchased\?page=1\&\S+/, { fixture: 'my_jamtracks_page1' }).as('getMyJamTracks_page1'); + }); + + it('should display the JamTracks', () => { + cy.get('input[type="search"]').type('ba'); + cy.wait('@getMyJamTracks_page1'); + cy.get('[data-testid=myJamTrackList]').should('contain', 'Back in Black by AC DC'); + }); + + it('clicking on a JamTrack should navigate to the JamTrack page', () => { + cy.get('input[type="search"]').type('ba'); + cy.wait('@getMyJamTracks_page1'); + cy.get('[data-testid=myJamTrackList] a').first().click(); + cy.url().should('include', '/jamtracks/1'); + }); + }) + + + +}); \ No newline at end of file diff --git a/jam-ui/cypress/fixtures/my_jamtracks_page1.json b/jam-ui/cypress/fixtures/my_jamtracks_page1.json new file mode 100644 index 000000000..d3066917a --- /dev/null +++ b/jam-ui/cypress/fixtures/my_jamtracks_page1.json @@ -0,0 +1,562 @@ + +{ + "next": 10, + "count": 3756, + "jamtracks": [ + { + "id": "1", + "name": "Back in Black", + "description": "This is a JamTrack audio file for use exclusively with the JamKazam service. This JamTrack is a high quality cover of the AC DC song \"Back in Black\".", + "recording_type": "Cover", + "original_artist": "AC DC", + "songwriter": null, + "publisher": null, + "sales_region": "Worldwide", + "price": "1.99", + "version": "0", + "duration": 221, + "year": null, + "plan_code": "jamtrack-acdc-backinblack", + "allow_free": true, + "download_price": "2.99", + "upgrade_price": "1.0", + "tracks": [ + { + "id": "103dea4d-f2a3-4414-8efe-d2ca378dda60", + "part": "Master Mix", + "instrument": { + "id": "computer", + "description": "Computer", + "created_at": "2021-02-02T23:16:46.168Z", + "updated_at": "2021-02-02T23:16:46.168Z", + "popularity": 3 + }, + "track_type": "Master", + "position": 1000, + "preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Master%20Mix-44100-preview-e9a5a63f34b4d523ee1842fff31f88ce.mp3", + "preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Master%20Mix-44100-preview-25fcba7ace7086e3cb6b97d7e33ba72e.ogg", + "preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Master%20Mix-44100-preview-9f0b072ed9f4b546e170fcdfb302137e.mp3" + }, + { + "id": "2755cbdd-0476-4f3b-9ba1-e2da561ddb4e", + "part": "Lead", + "instrument": { + "id": "voice", + "description": "Voice", + "created_at": "2021-02-02T23:16:46.168Z", + "updated_at": "2021-02-02T23:16:46.168Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 1, + "preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Vocal%20-%20Lead-44100-preview-d35c328fc3936dad9a79fe102dc72950.mp3", + "preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Vocal%20-%20Lead-44100-preview-b97b37651eae352fae3b3060918c7bcb.ogg", + "preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Vocal%20-%20Lead-44100-preview-d35c328fc3936dad9a79fe102dc72950.aac" + }, + { + "id": "0db7c4e1-5e8d-43fe-bd35-98acd8f68b26", + "part": "Drums", + "instrument": { + "id": "drums", + "description": "Drums", + "created_at": "2021-02-02T23:16:46.168Z", + "updated_at": "2021-02-02T23:16:46.168Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 2, + "preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Drums-44100-preview-03aadceb966caf40b96334bdd00234f6.mp3", + "preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Drums-44100-preview-854914e3e0d6fdc5f0794325b0ecaead.ogg", + "preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Drums-44100-preview-03aadceb966caf40b96334bdd00234f6.aac" + }, + { + "id": "2cc79ab6-dab8-4905-85e6-0df5f8e087f1", + "part": "Bass", + "instrument": { + "id": "bass guitar", + "description": "Bass Guitar", + "created_at": "2021-02-02T23:16:46.168Z", + "updated_at": "2021-02-02T23:16:46.168Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 3, + "preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Bass-44100-preview-61c334ac87f811bd010ed3a910764c2e.mp3", + "preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Bass-44100-preview-4066dafd7b72e9993b0c0fe1dba2b332.ogg", + "preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Bass-44100-preview-61c334ac87f811bd010ed3a910764c2e.aac" + }, + { + "id": "ed1d3487-3b32-442f-9c76-8a36fe3bb643", + "part": "Solo", + "instrument": { + "id": "electric guitar", + "description": "Electric Guitar", + "created_at": "2021-02-02T23:16:46.168Z", + "updated_at": "2021-02-02T23:16:46.168Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 4, + "preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Solo-44100-preview-e9fe8572a9ac1022762642cbd92b3c34.mp3", + "preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Solo-44100-preview-5fb058042254206cfa9fb4dcb0310b2c.ogg", + "preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Solo-44100-preview-e9fe8572a9ac1022762642cbd92b3c34.aac" + }, + { + "id": "f4ce7c91-7542-4e03-8fc2-68b31683d33e", + "part": "Rhythm 1", + "instrument": { + "id": "electric guitar", + "description": "Electric Guitar", + "created_at": "2021-02-02T23:16:46.168Z", + "updated_at": "2021-02-02T23:16:46.168Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 5, + "preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%201-44100-preview-6b498479823d4131a01fa535817d5eab.mp3", + "preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%201-44100-preview-f4cbb31dbde3e1a3e6012730a7e0e10f.ogg", + "preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%201-44100-preview-6b498479823d4131a01fa535817d5eab.aac" + }, + { + "id": "2d96c7ec-59f1-4d56-8a7f-7f4c75a0ccef", + "part": "Rhythm 2", + "instrument": { + "id": "electric guitar", + "description": "Electric Guitar", + "created_at": "2021-02-02T23:16:46.168Z", + "updated_at": "2021-02-02T23:16:46.168Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 6, + "preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%202-44100-preview-a626d7c632560f6737e1b6024141289e.mp3", + "preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%202-44100-preview-06a0e5af451f001f3465992efcd34ec0.ogg", + "preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%202-44100-preview-a626d7c632560f6737e1b6024141289e.aac" + }, + { + "id": "fce018ca-c897-4137-aa10-ef56a8e1831f", + "part": "Intro Scrapes", + "instrument": { + "id": "electric guitar", + "description": "Electric Guitar", + "created_at": "2021-02-02T23:16:46.168Z", + "updated_at": "2021-02-02T23:16:46.168Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 7, + "preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Intro%20Scrapes-44100-preview-0ddfaa7154e9ba35d05d60477d5dd3e9.mp3", + "preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Intro%20Scrapes-44100-preview-f53ce3c5f9dcf81af51560f52635fbb0.ogg", + "preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Intro%20Scrapes-44100-preview-0ddfaa7154e9ba35d05d60477d5dd3e9.aac" + }, + { + "id": "c9b3e0a8-4db0-4d0f-9769-398a6d56506e", + "part": "Main", + "instrument": { + "id": "electric guitar", + "description": "Electric Guitar", + "created_at": "2021-02-02T23:16:46.168Z", + "updated_at": "2021-02-02T23:16:46.168Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 8, + "preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Main-44100-preview-234a224f75a97d7ff8f55442ece6fcde.mp3", + "preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Main-44100-preview-828c9691f5435dea1c90182fa2618c9b.ogg", + "preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Main-44100-preview-234a224f75a97d7ff8f55442ece6fcde.aac" + }, + { + "id": "28c3df07-2a88-45a9-9ae6-3399a5d2eb20", + "part": "Sound FX", + "instrument": { + "id": "computer", + "description": "Computer", + "created_at": "2021-02-02T23:16:46.168Z", + "updated_at": "2021-02-02T23:16:46.168Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 9, + "preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Sound%20Effects-44100-preview-6c859c73036cd55bceb65f19f2d2f2f3.mp3", + "preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Sound%20Effects-44100-preview-f840d8df4c7388f776477139025ee712.ogg", + "preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Sound%20Effects-44100-preview-6c859c73036cd55bceb65f19f2d2f2f3.aac" + } + ], + "licensor": null, + "genres": ["Rock", "Pop"], + "added_cart": true, + "can_download": true, + "purchased": true + }, + { + "id": "531", + "name": "1234", + "description": "This is a JamTrack audio file for use exclusively with the JamKazam service. This JamTrack is a high quality cover of the Feist song \"1234\".", + "recording_type": "Cover", + "original_artist": "Feist", + "songwriter": null, + "publisher": null, + "sales_region": "Worldwide", + "price": "1.99", + "version": "1", + "duration": 184, + "year": 2007, + "plan_code": "jamtrack-feist-1234", + "allow_free": true, + "download_price": "2.99", + "upgrade_price": "1.0", + "tracks": [ + { + "id": "b834ce9c-2624-4977-a079-0b1b5d90ad6e", + "part": "Clicktrack", + "instrument": { + "id": "computer", + "description": "Computer", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Click", + "position": 10000, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234%20-%20Tency%20Music/1234%20Clicktrack-44100-preview-90bed87ea6402ab0f8d283ffe094c95f.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234%20-%20Tency%20Music/1234%20Clicktrack-44100-preview-7198bae1519e40827aff0bd704e2066b.ogg", + "preview_aac_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234%20-%20Tency%20Music/1234%20Clicktrack-44100-preview-90bed87ea6402ab0f8d283ffe094c95f.aac" + }, + { + "id": "b5a67d64-f94f-453e-9dab-691304275bc2", + "part": "Master Mix", + "instrument": { + "id": "computer", + "description": "Computer", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Master", + "position": 1000, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1%202%203%204%20Master%20Mix-44100-preview-5fe2a923a614f17dd9c6440b65c1e884.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1%202%203%204%20Master%20Mix-44100-preview-aaefd823d7deaa1bc862eb8ec1e53fe3.ogg", + "preview_aac_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1%202%203%204%20Master%20Mix-44100-preview-6d3edecd174080e88e611984969f1b2d.aac" + }, + { + "id": "27353eb1-9f2b-487b-9047-93f49446b4db", + "part": "Lead", + "instrument": { + "id": "voice", + "description": "Voice", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 1, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Vocal%20-%20Lead-44100-preview-426d923380d10fbdf2d5a4e4108b0de2.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Vocal%20-%20Lead-44100-preview-30eaef3aea1499493cbad76c5c3c8a50.ogg", + "preview_aac_url": null + }, + { + "id": "78736d23-e657-4922-b145-9f7db40bb36e", + "part": "Backing", + "instrument": { + "id": "voice", + "description": "Voice", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 2, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Vocal%20-%20Backing-44100-preview-c0fb7721f3c8cd3253c8c5a6d6b034dd.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Vocal%20-%20Backing-44100-preview-b7145437bbb6b01b566f10ef9009d001.ogg", + "preview_aac_url": null + }, + { + "id": "1978c439-115b-4214-85a6-beec780310a1", + "part": "Drums", + "instrument": { + "id": "drums", + "description": "Drums", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 3, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Drums%20-%20Drums-44100-preview-da3d7e78b9a7b50bea7bcc8f13a7d4b0.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Drums%20-%20Drums-44100-preview-d320dc7600c6d9c08af19b813d6d8176.ogg", + "preview_aac_url": null + }, + { + "id": "8457c55d-924d-4048-8c5f-46b5c7668552", + "part": "Bass", + "instrument": { + "id": "bass guitar", + "description": "Bass Guitar", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 4, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Bass%20Guitar%20-%20Bass-44100-preview-c4b1ce442a9645f6ead0f078afe48d3d.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Bass%20Guitar%20-%20Bass-44100-preview-8a0b0d664802015a219f3320d4d5c0cd.ogg", + "preview_aac_url": null + }, + { + "id": "ca5d5597-1a19-45b1-9d1b-478f6b6c4b19", + "part": "Piano", + "instrument": { + "id": "piano", + "description": "Piano", + "created_at": "2014-02-16T13:10:07.059Z", + "updated_at": "2014-02-16T13:10:07.059Z", + "popularity": 2 + }, + "track_type": "Track", + "position": 5, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Piano%20-%20Piano-44100-preview-208fb9e053bb445c1d55ec443809211c.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Piano%20-%20Piano-44100-preview-8940844b3972b39ad9b786805496bc1b.ogg", + "preview_aac_url": null + }, + { + "id": "755c6c48-fc6c-4dc8-bbf2-9dc0d0a5f2a8", + "part": "Acoustic", + "instrument": { + "id": "acoustic guitar", + "description": "Acoustic Guitar", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 6, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Acoustic%20Guitar%20-%20Acoustic-44100-preview-11bde0963b7a833072a49c1096a0b6ef.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Acoustic%20Guitar%20-%20Acoustic-44100-preview-92c44a32feac702880796fd9d6d5f883.ogg", + "preview_aac_url": null + }, + { + "id": "508bcbaa-4d29-44c0-8cdd-f57fd3fee717", + "part": "Banjo", + "instrument": { + "id": "banjo", + "description": "Banjo", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 2 + }, + "track_type": "Track", + "position": 7, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Banjo%20-%20Banjo-44100-preview-6ed9db0acb0616651e297b0c057f453d.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Banjo%20-%20Banjo-44100-preview-1e18e0b352e4b05fefa35ce7fd9c84a1.ogg", + "preview_aac_url": null + }, + { + "id": "6ef8af53-6615-450c-b78b-4310fb0e0395", + "part": "Strings", + "instrument": { + "id": "orchestra", + "description": "Orchestra", + "created_at": "2015-08-11T16:08:58.806Z", + "updated_at": "2015-08-11T16:08:58.806Z", + "popularity": 1 + }, + "track_type": "Track", + "position": 8, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Orchestra%20-%20Strings-44100-preview-7017822e5edaedbe91fea259cc29666c.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Orchestra%20-%20Strings-44100-preview-70f5d96ed08b1d6a625f21c8be3f691c.ogg", + "preview_aac_url": null + }, + { + "id": "91427115-63be-49e6-adb1-078f4a7f7ae8", + "part": "Trumpet", + "instrument": { + "id": "trumpet", + "description": "Trumpet", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 2 + }, + "track_type": "Track", + "position": 9, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Trumpet%20-%20Trumpet-44100-preview-74d7ab8c5af40dc9768176df2afd691a.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Trumpet%20-%20Trumpet-44100-preview-df093dfebc96d3c22c13ed8d14b44ed0.ogg", + "preview_aac_url": null + } + ], + "licensor": { "id": "027d90a1-b126-4d5a-8af6-3167296dfb04", "name": "Tency Music" }, + "genres": ["Folk", "Alternative Rock"], + "added_cart": false, + "can_download": false, + "purchased": false + }, + { + "id": "1437", + "name": "18 And Life", + "description": "This is a JamTrack audio file for use exclusively with the JamKazam service. This JamTrack is a high quality cover of the Skid Row song \"18 And Life\".", + "recording_type": "Cover", + "original_artist": "Skid Row", + "songwriter": null, + "publisher": null, + "sales_region": "Worldwide", + "price": "1.99", + "version": "1", + "duration": 227, + "year": 1989, + "plan_code": "jamtrack-skidrow-18andlife", + "allow_free": true, + "download_price": "2.99", + "upgrade_price": "1.0", + "tracks": [ + { + "id": "7c515f02-bebd-4fdd-b30a-81b72ec277b9", + "part": "Clicktrack", + "instrument": { + "id": "computer", + "description": "Computer", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Click", + "position": 10000, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life%20-%20Tency%20Music/click-44100-preview-424086caaa67c89532635ef0970b2d75.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life%20-%20Tency%20Music/click-44100-preview-d30de7c1353826896110d3ce5f459b23.ogg", + "preview_aac_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life%20-%20Tency%20Music/click-44100-preview-424086caaa67c89532635ef0970b2d75.aac" + }, + { + "id": "db0a34e4-71e9-4342-b04a-e7c7f068b4fb", + "part": "Master Mix", + "instrument": { + "id": "computer", + "description": "Computer", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Master", + "position": 1000, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Master%20Mix-44100-preview-5bf5b2872e898dc43875f829e238b62b.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Master%20Mix-44100-preview-3ba1eb2b8ab936212cc299cfb8db34ac.ogg", + "preview_aac_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Master%20Mix-44100-preview-146e9a850f83a2f76dc31dc9489dc3aa.aac" + }, + { + "id": "cc237bfd-5d87-413b-a460-55d17594f785", + "part": "Lead", + "instrument": { + "id": "voice", + "description": "Voice", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 1, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/ld-44100-preview-04a953ee8607a97e8533ea5adf4560a1.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/ld-44100-preview-3486ef50eb889b71208040a0a13de52f.ogg", + "preview_aac_url": null + }, + { + "id": "a182cf33-1d61-41a8-8e9b-fd23d501885c", + "part": "Drums", + "instrument": { + "id": "drums", + "description": "Drums", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 2, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/drums-44100-preview-7ec143f7aa0dc019a2af48c6861c400b.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/drums-44100-preview-6fd8eacb6a8bd35a85e0d4a3a8ec120c.ogg", + "preview_aac_url": null + }, + { + "id": "406c1f87-c6c1-406f-85a9-05768267ff46", + "part": "Bass", + "instrument": { + "id": "bass guitar", + "description": "Bass Guitar", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 3, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/bass-44100-preview-37326a28b8d55f4b61a00eb7406a4da9.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/bass-44100-preview-ff2e87a89ae7693fa8f15a3d065c5833.ogg", + "preview_aac_url": null + }, + { + "id": "fa46fcd7-0647-4f94-93fd-bddb403abc8b", + "part": "Lead", + "instrument": { + "id": "electric guitar", + "description": "Electric Guitar", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 4, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Lead-44100-preview-7b8ac822d2a0ccf341c4607919e5125a.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Lead-44100-preview-3d13650573ebe20f939a7e2d661f9fab.ogg", + "preview_aac_url": null + }, + { + "id": "42e6c71e-715c-48b9-b000-fb7fdabd3fe3", + "part": "Rhythm Distorted", + "instrument": { + "id": "electric guitar", + "description": "Electric Guitar", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 5, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%20Distorted-44100-preview-4f0312e6d429fa211c873ecd671c2629.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%20Distorted-44100-preview-36e75c706ff27930a54be1159afafd9a.ogg", + "preview_aac_url": null + }, + { + "id": "a16a69b1-2b89-4bca-8039-bb927c7f517f", + "part": "Arpeggios Clean", + "instrument": { + "id": "electric guitar", + "description": "Electric Guitar", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 6, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Arpeggios%20Clean-44100-preview-f1f3df4288f9ac9bd8183303099f1a40.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Arpeggios%20Clean-44100-preview-f8da9761dbed9afd32d636fb0ba2f757.ogg", + "preview_aac_url": null + }, + { + "id": "8246f3fb-6d35-4a31-9bcd-ef81fd39c66f", + "part": "Arpeggios Distorted", + "instrument": { + "id": "electric guitar", + "description": "Electric Guitar", + "created_at": "2013-01-03T01:57:43.040Z", + "updated_at": "2013-01-03T01:57:43.040Z", + "popularity": 3 + }, + "track_type": "Track", + "position": 7, + "preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Arpeggios%20Distorted-44100-preview-2bf523d0f429eaff366691fff0dbcb5f.mp3", + "preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Arpeggios%20Distorted-44100-preview-e25718a81d9d0a011746def84547f1e9.ogg", + "preview_aac_url": null + } + ], + "licensor": { "id": "027d90a1-b126-4d5a-8af6-3167296dfb04", "name": "Tency Music" }, + "genres": ["Metal", "Rock", "Hard Rock"], + "added_cart": false, + "can_download": false, + "purchased": false + } + ] +} diff --git a/jam-ui/src/components/jamtracks/JKCreateCustomMix.js b/jam-ui/src/components/jamtracks/JKCreateCustomMix.js index c67565a38..861e15da9 100644 --- a/jam-ui/src/components/jamtracks/JKCreateCustomMix.js +++ b/jam-ui/src/components/jamtracks/JKCreateCustomMix.js @@ -1,13 +1,19 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { Table, Row, Col, Input, Button } from 'reactstrap'; -import JKInstrumentIcon from '../profile/JKInstrumentIcon'; import Select from 'react-select'; import { useForm, Controller } from 'react-hook-form'; -import { createMixdown } from '../../helpers/rest'; +import { createMyMixdown, addMixdown } from '../../store/features/jamTrackSlice'; +import { useDispatch, useSelector } from 'react-redux'; +import { Scrollbar } from 'react-scrollbars-custom'; + +const JKCreateCustomMix = () => { + const MAX_MIXDOWNS = 5; -const JKCreateCustomMix = ({ jamTrack }) => { const [tracks, setTracks] = useState([]); - //const [selectedTracks, setSelectedTracks] = useState([]); + const [mixdowns, setMixdowns] = useState([]); + const [selectedTracks, setSelectedTracks] = useState([]); + const dispatch = useDispatch(); + const scrollbar = useRef(); const TEMPO_OPTIONS = [ { value: '0', label: 'Original tempo' }, @@ -61,6 +67,9 @@ const JKCreateCustomMix = ({ jamTrack }) => { { value: '12', label: 'Up 12 semitone' } ]; + const jamTrack = useSelector(state => state.jamTrack.jamTrack); + const newMixdownLoadingStatus = useSelector(state => state.jamTrack.newMixdownLoadingStatus); + const { control, handleSubmit, @@ -81,13 +90,13 @@ const JKCreateCustomMix = ({ jamTrack }) => { mixdownTracks: [] } }); + const onSubmit = data => { - console.log('data', data); const _tracks = []; let countIn = false; - const selectedTracks = getValues('mixdownTracks'); + const selected = getValues('mixdownTracks'); tracks.forEach(track => { - const muted = selectedTracks.includes(track.id); + const muted = selected.includes(track.id); if (track.id === 'count-in') { if (countIn === false) { countIn = !muted; @@ -95,7 +104,7 @@ const JKCreateCustomMix = ({ jamTrack }) => { } else { _tracks.push({ id: track.id, - mute: selectedTracks.includes(track.id) + mute: selected.includes(track.id) }); } }); @@ -105,39 +114,46 @@ const JKCreateCustomMix = ({ jamTrack }) => { const mixData = { jamTrackID: jamTrack.id, name: data.mixName, - settings: { speed: data.tempo.value, pitch: data.pitch.value, 'count-in': countIn, tracks: _tracks } + settings: { speed: parseInt(data.tempo.value), pitch: parseInt(data.pitch.value), 'count-in': countIn, tracks: _tracks } }; - console.log('mixData', mixData); + const tempMixdown = {...mixData, id: 'temp', jam_track_id: jamTrack.id}; + dispatch(addMixdown(tempMixdown)); - createMixdown(mixData) - .then(response => { - console.log('mixdown created', response); - //TODO: add this mixdown to global state of jamtrack mixdowns - }) - .catch(error => { - console.error('mixdown create error', error); - }); + dispatch(createMyMixdown(mixData)); }; const toggleTrack = e => { const trackId = e.target.value; - const selectedTracks = getValues('mixdownTracks'); - if (selectedTracks.includes(trackId)) { - //setSelectedTracks(selectedTracks.filter(track => track !== trackId)); + const selected = getValues('mixdownTracks'); + if (selected.includes(trackId)) { setValue('mixdownTracks', selectedTracks.filter(track => track !== trackId)); } else { - //setSelectedTracks([...selectedTracks, trackId]); setValue('mixdownTracks', [...selectedTracks, trackId]); } + setSelectedTracks(getValues('mixdownTracks')); }; useEffect(() => { if (jamTrack) { setTracks(jamTrack.tracks.filter(track => track.track_type === 'Track' || track.track_type === 'Click')); + setMixdowns(jamTrack.mixdowns); } }, [jamTrack]); + useEffect(() => { + if (jamTrack) { + if(newMixdownLoadingStatus === 'succeeded') { + setValue('mixName', ''); + setValue('tempo', TEMPO_OPTIONS[0]); + setValue('pitch', PITCH_OPTIONS[0]); + setValue('mixdownTracks', []); + setSelectedTracks([]); + setMixdowns(jamTrack.mixdowns); + } + } + }, [newMixdownLoadingStatus]); + const trackName = track => { if (track.track_type === 'Track' || track.track_type === 'Click') { if (track.track_type === 'Click') { @@ -153,38 +169,42 @@ const JKCreateCustomMix = ({ jamTrack }) => { } }; + const hasExceededMax = mixdowns.length >= MAX_MIXDOWNS; + return ( <>

Mute any tracks you like. Adjust the pitch or tempo of playback. Then give your mix a descriptive name, and click the Create Mix button. It will take few minutes for us to create your custom mix.

-
- + +
- + + {tracks && tracks.map((track, index) => ( - ))} +
Tracks {tracks.length > 0 && <>({tracks.length})}MuteMute
- - {trackName(track)} + {trackName(track)} - + +
+ {
- - Tempo + + Tempo } /> - - Pitch + + Pitch } /> - - Mix Name + + Mix Name { rules={{ required: 'Mix name is required' }} - render={({ field }) => } + render={({ field }) => } /> {errors.mixName && (
@@ -240,8 +260,10 @@ const JKCreateCustomMix = ({ jamTrack }) => { - - + + diff --git a/jam-ui/src/components/jamtracks/JKJamTrack.js b/jam-ui/src/components/jamtracks/JKJamTrack.js index 6acd83bdb..900e58d3a 100644 --- a/jam-ui/src/components/jamtracks/JKJamTrack.js +++ b/jam-ui/src/components/jamtracks/JKJamTrack.js @@ -1,37 +1,34 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useResponsive } from '@farfetch/react-context-responsive'; import { useParams } from 'react-router-dom'; -import { Card, CardBody, Row, Col, Progress } from 'reactstrap'; +import { Card, CardBody, Row, Col } from 'reactstrap'; import FalconCardHeader from '../common/FalconCardHeader'; -import { getJamTrack, getUserDetail, postUserEvent, userOpenedJamTrackWebPlayer } from '../../helpers/rest'; +import { getUserDetail, postUserEvent, userOpenedJamTrackWebPlayer } from '../../helpers/rest'; import JKJamTrackPlayer from './JKJamTrackPlayer'; import JKMyJamTrackMixes from './JKMyJamTrackMixes'; import JKCreateCustomMix from './JKCreateCustomMix'; import { useAuth } from '../../context/UserAuth'; +import { fetchJamTrack } from '../../store/features/jamTrackSlice'; +import { useDispatch, useSelector } from 'react-redux'; + const JKJamTrack = () => { + console.log('JKJamTrack rendering'); + const { t } = useTranslation('jamtracks'); const { greaterThan } = useResponsive(); const { id } = useParams(); - const [jamTrack, setJamTrack] = useState(null); - const [loading, setLoading] = useState(false); const { currentUser } = useAuth(); - const fetchJamTrack = async () => { - console.log('fetching jam track', id); - try { - setLoading(true); - const resp = await getJamTrack({ id }); - const data = await resp.json(); - console.log('jam track 123', data); - setJamTrack(data); - } catch (error) { - console.log('Error when fetching jam track', error); - } finally { - setLoading(false); - } + const dispatch = useDispatch(); + + const jamTrack = useSelector(state => state.jamTrack.jamTrack); + const jamTrackLoadingStatus = useSelector(state => state.jamTrack.status); + + const fetchJamTrackRecord = () => { + dispatch(fetchJamTrack({ id })); }; const fetchUserDetail = async () => { @@ -58,31 +55,36 @@ const JKJamTrack = () => { }, [currentUser, jamTrack]); useEffect(() => { - fetchJamTrack(); + fetchJamTrackRecord(); }, [id]); return ( - - - - - {jamTrack && } - - - - {jamTrack && } - - - - - - - { jamTrack && } - - - - - + <> + {jamTrackLoadingStatus === 'loading' || jamTrackLoadingStatus == 'idel' ? ( +
Loading...
+ ) : Object.keys(jamTrack).length ? ( + + + + + {jamTrack && } + + + + {jamTrack && } + + + + + + {jamTrack && } + + + + + + ) : null} + ); }; diff --git a/jam-ui/src/components/jamtracks/JKJamTrackPlayer.js b/jam-ui/src/components/jamtracks/JKJamTrackPlayer.js index aeef561bb..7963e39f5 100644 --- a/jam-ui/src/components/jamtracks/JKJamTrackPlayer.js +++ b/jam-ui/src/components/jamtracks/JKJamTrackPlayer.js @@ -1,22 +1,20 @@ import React, { useState, useEffect, useRef } from 'react'; import Select from 'react-select'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Row, Col } from 'reactstrap'; -import PropTypes from 'prop-types'; -import { markMixdownActive } from '../../helpers/rest'; import FingerprintJS from '@fingerprintjs/fingerprintjs'; +import { useSelector } from 'react-redux'; -const JKJamTrackPlayer = ({ jamTrack }) => { +const JKJamTrackPlayer = () => { const [options, setOptions] = useState([]); const [selectedOption, setSelectedOption] = useState(null); const fpPromise = FingerprintJS.load(); const [audioUrl, setAudioUrl] = useState(null); const audioRef = useRef(null); + const jamTrack = useSelector(state => state.jamTrack.jamTrack); useEffect(() => { if (jamTrack) { - console.log('_JamTrackPlayer_ jamTrack', jamTrack); - const opts = jamTrack.mixdowns.map(mix => ({ value: mix.id, label: mix.name })); + const opts = jamTrack.mixdowns.map(mix => ({ value: mix.id, label: mix.name })).filter(mix => mix.value !== 'temp'); opts.unshift({ value: 'original', label: 'Original' }); setOptions(opts); if (jamTrack.last_mixdown_id) { @@ -37,8 +35,6 @@ const JKJamTrackPlayer = ({ jamTrack }) => { return; } - console.log('_JamTrackPlayer_ selectedOption', selectedOption); - if (selectedOption.value === 'original') { const audioUrl = getMasterTrack(); setAudioUrl(audioUrl); @@ -56,7 +52,6 @@ const JKJamTrackPlayer = ({ jamTrack }) => { const getMasterTrack = () => { const masterTrack = jamTrack.tracks.find(track => track.track_type === 'Master'); - console.log('_JamTrackPlayer_ master', masterTrack); if (masterTrack) { const audioUrl = masterTrack.preview_mp3_url; return audioUrl; @@ -91,8 +86,4 @@ const JKJamTrackPlayer = ({ jamTrack }) => { ); }; -JKJamTrackPlayer.propTypes = { - jamTrack: PropTypes.object.isRequired -}; - -export default JKJamTrackPlayer; +export default JKJamTrackPlayer; \ No newline at end of file diff --git a/jam-ui/src/components/jamtracks/JKMyJamTrackMixes.js b/jam-ui/src/components/jamtracks/JKMyJamTrackMixes.js index f4387f12d..5d170f93f 100644 --- a/jam-ui/src/components/jamtracks/JKMyJamTrackMixes.js +++ b/jam-ui/src/components/jamtracks/JKMyJamTrackMixes.js @@ -1,71 +1,121 @@ import React, { useState, useEffect } from 'react'; import { Table } from 'reactstrap'; import FingerprintJS from '@fingerprintjs/fingerprintjs'; +import { removeMixdown } from '../../store/features/jamTrackSlice'; +import { useDispatch, useSelector } from 'react-redux'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -const JKMyJamTrackMixes = ({ jamTrack }) => { +const JKMyJamTrackMixes = () => { const [mixes, setMixes] = useState([]); const fpPromise = FingerprintJS.load(); + const dispatch = useDispatch(); + + const jamTrack = useSelector(state => state.jamTrack.jamTrack); + const mixdownsLoadingStatus = useSelector(state => state.jamTrack.mixdownsLoadingStatus); + const deleteMixdownStatus = useSelector(state => state.jamTrack.deleteMixdownStatus); + const tempMixdownLoadingStatus = useSelector(state => state.jamTrack.tempMixdownLoadingStatus); useEffect(() => { - if(!jamTrack) { + if (!jamTrack) { return; } - setMixes(jamTrack.mixdowns) - }, []); + if (mixdownsLoadingStatus === 'succeeded') { + setMixes(jamTrack.mixdowns.filter(m => m.id !== 'temp')); + } + }, [mixdownsLoadingStatus]); + + useEffect(() => { + if (tempMixdownLoadingStatus === 'succeeded') { + setMixes(jamTrack.mixdowns); + } + }, [tempMixdownLoadingStatus]); const downloadJamTrack = async () => { console.log('Downloading JamTrack'); - if(!jamTrack.can_download) { + if (!jamTrack.can_download) { console.log('Cannot download JamTrack'); - return + return; } const fp = await fpPromise; const result = await fp.get(); - const redirectTo = `${process.env.REACT_APP_API_BASE_URL}/jamtracks/${jamTrack.id}/stems/master/download.mp3?file_type=mp3&download=1&mark=${result.visitorId}`; - window.open(redirectTo, '_blank'); - } + const src = `${process.env.REACT_APP_API_BASE_URL}/jamtracks/${ + jamTrack.id + }/stems/master/download.mp3?file_type=mp3&download=1&mark=${result.visitorId}`; + openDownload(src); + }; - const downloadMix = async (mixId) => { - console.log('Download mixdown') + const downloadMix = async mixId => { + console.log('Download mixdown'); const mixdown = mixes.find(m => m.id === mixId); const mixdownPackage = mixdown.packages.find(p => p.file_type === 'mp3'); - if(mixdownPackage?.signing_state == 'SIGNED'){ + if (mixdownPackage?.signing_state == 'SIGNED') { const fp = await fpPromise; const result = await fp.get(); - const redirectTo = `${process.env.REACT_APP_API_BASE_URL}/mixdowns/${mixdown.id}/download.mp3?file_type=mp3&sample_rate=48&download=1&mark=${result.visitorId}` - window.open(redirectTo, '_blank'); + const src = `${process.env.REACT_APP_API_BASE_URL}/mixdowns/${ + mixdown.id + }/download.mp3?file_type=mp3&sample_rate=48&download=1&mark=${result.visitorId}`; + openDownload(src); + }else{ + console.log('Mixdown not signed'); } - } + }; - const deleteMix = (mixId) => { - if(window.confirm("Delete this custom mix?")){ - console.log("Deleting mixdown", mixId) + const openDownload = async src => { + const iframe = document.createElement('iframe'); + iframe.src = src; + iframe.style.display = 'none'; + document.body.appendChild(iframe); + }; + + const deleteMix = mixId => { + if (window.confirm('Delete this custom mix?')) { + console.log('Deleting mixdown', mixId); + dispatch(removeMixdown({ id: mixId })); } - } + }; return ( <> -

You can save a maximum of 5 mixes on JamKazam. If you need to make more mixes, download a mix to save it, then delete it to make more room

- +

+ You can save a maximum of 5 mixes on JamKazam. If you need to make more mixes, download a mix + to save it, then delete it to make more room +

+
- + - {mixes.map(mix => ( - ))} diff --git a/jam-ui/src/components/jamtracks/JKMyJamTracks.js b/jam-ui/src/components/jamtracks/JKMyJamTracks.js index e4c5498c1..e6f484ed0 100644 --- a/jam-ui/src/components/jamtracks/JKMyJamTracks.js +++ b/jam-ui/src/components/jamtracks/JKMyJamTracks.js @@ -3,33 +3,35 @@ import { Card, CardBody, ListGroup, ListGroupItem, FormGroup, Input, InputGroup, import FalconCardHeader from '../common/FalconCardHeader'; import { useTranslation } from 'react-i18next'; import { useResponsive } from '@farfetch/react-context-responsive'; -import { getPurchasedJamTracks } from '../../helpers/rest'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import useOnScreen from '../../hooks/useOnScreen'; import { Link } from 'react-router-dom'; +import { fetchMyJamTracks } from '../../store/features/myJamTracksSlice'; +import { useDispatch, useSelector } from 'react-redux'; const JKMyJamTracks = () => { const { t } = useTranslation('jamtracks'); const { greaterThan } = useResponsive(); - const [jamTracks, setJamTracks] = useState([]); - const [loading, setLoading] = useState(false); const [inputValue, setInputValue] = useState(''); const inputRef = React.createRef(); const containerRef = useRef(null); const [lastJamTrackRef, setLastJamTrackRef] = useState(null); const isIntersecting = useOnScreen({ current: lastJamTrackRef }); - const [nextPage, setNextPage] = useState(1); + + const dispatch = useDispatch(); + + const jamTracks = useSelector(state => state.myJamTrack.jamTracks); + const loadingStatus = useSelector(state => state.myJamTrack.status); + const nextPage = useSelector(state => state.myJamTrack.next); const handleInputChange = e => { const val = e.target.value; setInputValue(val); - // const params = { page: 1, search: val }; - // fetchJamTracks(params); }; useEffect(() => { - const getMyJamTracks = setTimeout(() => { - fetchJamTracks({ page: 1, search: inputValue}); + const getMyJamTracks = setTimeout(async () => { + await fetchJamTracks({ page: 1, search: inputValue}); }, 1000); return () => clearTimeout(getMyJamTracks); }, [inputValue]); @@ -37,37 +39,23 @@ const JKMyJamTracks = () => { const fetchJamTracks = async (params) => { const { page } = params; try { - setLoading(true); - const resp = await getPurchasedJamTracks(params); - const data = await resp.json(); - if (page === 1) { - setJamTracks(data.jamtracks); - }else{ - setJamTracks(prev => [...prev, ...data.jamtracks]); - } - setNextPage(data.next); - + dispatch(fetchMyJamTracks(params)); } catch (error) { console.log('Error when fetching jam tracks', error); } finally { - setLoading(false); + //setLoading(false); } }; useEffect(() => { if (isIntersecting) { - if (nextPage && !loading && nextPage !== 1) { + if (nextPage && loadingStatus !== 'loading' && nextPage !== 1) { const params = { page: nextPage }; fetchJamTracks(params); } } }, [isIntersecting]); - useEffect(() => { - const params = { page: nextPage }; - fetchJamTracks(params); - }, []); - const containerStyle = { display: 'flex', flexDirection: 'column', @@ -83,7 +71,7 @@ const JKMyJamTracks = () => {
- {loading ? ( + {loadingStatus === 'loading' ? (
- - {jamTracks.map((jamTrack, index) => ( -
(jamTracks.length - 1 === index ? setLastJamTrackRef(ref) : null)}> - - {jamTrack.name} - {jamTrack.original_artist && ` by ${jamTrack.original_artist}`} - -
- - ))} -
- { loading &&
Loading...
} + { loadingStatus === 'loading' ? ( +
Loading...
+ ) : loadingStatus === 'failed' ? ( +
Error loading jam tracks
+ ) : loadingStatus === 'succeeded' ? ( + + {jamTracks && jamTracks.map((jamTrack, index) => ( +
(jamTracks.length - 1 === index ? setLastJamTrackRef(ref) : null)}> + + {jamTrack.name} + {jamTrack.original_artist && ` by ${jamTrack.original_artist}`} + +
+ + ))} +
+ ) : null } + +
diff --git a/jam-ui/src/helpers/initFA.js b/jam-ui/src/helpers/initFA.js index ba8298c14..6caf53261 100644 --- a/jam-ui/src/helpers/initFA.js +++ b/jam-ui/src/helpers/initFA.js @@ -35,8 +35,11 @@ import { faPaperPlane as farPaperPlane, faQuestionCircle as farQuestionCircle, faSmileBeam as farSmileBeam, - faStar as farStar + faStar as farStar, + faMinus as farMinus, + far, } from '@fortawesome/free-regular-svg-icons'; + import { faAlignLeft, faAlignRight, @@ -164,7 +167,9 @@ import { faPlayCircle, faPauseCircle, faStopCircle, - faInfoCircle + faInfoCircle, + faDownload, + } from '@fortawesome/free-solid-svg-icons'; //import { faAcousticGuitar } from "../icons"; @@ -339,6 +344,7 @@ library.add( farCircle, farCopy, farComment, - + faMinus, + faDownload, //faAcousticGuitar, ); diff --git a/jam-ui/src/helpers/rest.js b/jam-ui/src/helpers/rest.js index e12f09ef0..3cee9ed3a 100644 --- a/jam-ui/src/helpers/rest.js +++ b/jam-ui/src/helpers/rest.js @@ -389,6 +389,7 @@ export const autocompleteJamTracks = (input, limit) => { }; export const getPurchasedJamTracks = (options = {}) => { + options = { ...options, show_purchased_only: true }; return new Promise((resolve, reject) => { apiFetch(`/jamtracks/purchased?${new URLSearchParams(options)}`) .then(response => resolve(response)) @@ -482,7 +483,7 @@ export const placeOrder = () => { export const postUserEvent = (options = {}) => { return new Promise((resolve, reject) => { - apiFetch(`users/event/record`, { + apiFetch(`/users/event/record`, { method: 'POST', body: JSON.stringify(options) }) @@ -493,7 +494,7 @@ export const postUserEvent = (options = {}) => { export const userOpenedJamTrackWebPlayer = () => { return new Promise((resolve, reject) => { - apiFetch(`/api/users/progression/opened_jamtrack_web_player`, { + apiFetch(`/users/progression/opened_jamtrack_web_player`, { method: 'POST' }) .then(response => resolve(response)) @@ -522,4 +523,14 @@ export const createMixdown = options => { .then(response => resolve(response)) .catch(error => reject(error)); }); +} + +export const deleteMixdown = id => { + return new Promise((resolve, reject) => { + apiFetch(`/mixdowns/${id}`, { + method: 'DELETE' + }) + .then(response => resolve(response)) + .catch(error => reject(error)); + }); } \ No newline at end of file diff --git a/jam-ui/src/store/features/jamTrackSlice.js b/jam-ui/src/store/features/jamTrackSlice.js new file mode 100644 index 000000000..251c704f9 --- /dev/null +++ b/jam-ui/src/store/features/jamTrackSlice.js @@ -0,0 +1,101 @@ +import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; +import { deleteMixdown, getJamTrack, createMixdown } from '../../helpers/rest'; + +const initialState = { + jamTrack: {}, + jamTrackLoadingStatus: 'idle', + mixdownsLoadingStatus: 'idle', + deleteMixdownStatus: 'idle', + newMixdownLoadingStatus: 'idle', + tempMixdownLoadingStatus: 'idle', + + error: null +} + +export const fetchJamTrack = createAsyncThunk('jamTracks/fetchJamTrack', async(options, thunkAPI) => { + const response = await getJamTrack(options) + return response.json(); +}); + +export const createMyMixdown = createAsyncThunk('jamTracks/createMixdown', async(options, thunkAPI) => { + const response = await createMixdown(options) + return response.json(); +}); + +export const removeMixdown = createAsyncThunk('jamTracks/removeMixdown', async(options, thunkAPI) => { + console.log('removeMixdown', options); + const { id } = options; + const response = await deleteMixdown(id) + return { id }; +}); + +export const jamTrackSlice = createSlice({ + name: 'jamTrack', + initialState, + reducers: { + addMixdown: (state, action) => { + const payload = action.payload; + const jamTrack = state.jamTrack; + if (jamTrack) { + state.jamTrack.mixdowns = [...jamTrack.mixdowns, payload]; + state.tempMixdownLoadingStatus = 'succeeded'; + } + }, + }, + extraReducers: builder => { + builder + .addCase(fetchJamTrack.pending, (state, action) => { + state.jamTrackLoadingStatus = 'loading' + state.mixdownsLoadingStatus = 'loading' + }) + .addCase(fetchJamTrack.fulfilled, (state, action) => { + state.jamTrack = action.payload + state.jamTrackLoadingStatus = 'succeeded' + + if (action.payload.mixdowns) { + state.mixdownsLoadingStatus = 'succeeded' + } + }) + .addCase(fetchJamTrack.rejected, (state, action) => { + state.status = 'failed' + state.jamTrackLoadingStatus = 'failed' + state.mixdownsLoadingStatus = 'failed' + state.error = action.error.message; + }) + .addCase(createMyMixdown.pending, (state, action) => { + state.newMixdownLoadingStatus = 'loading' + state.mixdownsLoadingStatus = 'loading' + }) + .addCase(createMyMixdown.fulfilled, (state, action) => { + state.jamTrack.mixdowns = [...state.jamTrack.mixdowns, action.payload]; + state.newMixdownLoadingStatus = 'succeeded' + state.mixdownsLoadingStatus = 'succeeded' + state.tempMixdownLoadingStatus = 'idle' + }) + .addCase(createMyMixdown.rejected, (state, action) => { + state.error = action.error.message; + state.newMixdownLoadingStatus = 'failed' + state.tempMixdownLoadingStatus = 'idle' + }) + .addCase(removeMixdown.pending, (state, action) => { + state.mixdownsLoadingStatus = 'loading' + state.deleteMixdownStatus = 'loading' + }) + .addCase(removeMixdown.fulfilled, (state, action) => { + console.log('mixdown removed', action.payload) + const mixdowns = state.jamTrack.mixdowns.filter(mix => mix.id !== action.payload.id); + state.jamTrack.mixdowns = mixdowns; + state.mixdowns = mixdowns; + state.mixdownsLoadingStatus = 'succeeded' + state.deleteMixdownStatus = 'succeeded' + }) + .addCase(removeMixdown.rejected, (state, action) => { + state.error = action.error.message; + state.mixdownsLoadingStatus = 'failed' + state.deleteMixdownStatus = 'failed' + }) + } +}); + +export const { addMixdown } = jamTrackSlice.actions; +export default jamTrackSlice.reducer; \ No newline at end of file diff --git a/jam-ui/src/store/features/myJamTracksSlice.js b/jam-ui/src/store/features/myJamTracksSlice.js new file mode 100644 index 000000000..20a6d349e --- /dev/null +++ b/jam-ui/src/store/features/myJamTracksSlice.js @@ -0,0 +1,63 @@ +import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; +import { getPurchasedJamTracks } from '../../helpers/rest'; + +const initialState = { + jamTracks: [], + status: 'idle', + error: null, + next: null, +}; + +export const fetchMyJamTracks = createAsyncThunk('jamTracks/fetchMyJamTracks', async (options, thunkAPI) => { + + const response = await getPurchasedJamTracks(options); + return response.json(); +}); + + +export const myJamTracksSlice = createSlice({ + name: 'jamTracks', + initialState, + reducers: { + addJamTrack: (state, action) => { + state.jamTracks.push(action.payload); + }, + // updateJamTrack: (state, action) => { + // const { id, name } = action.payload; + // const existingJamTrack = state.jamTracks.find(jamTrack => jamTrack.id === id); + // if (existingJamTrack) { + // existingJamTrack.name = name; + // } + // }, + deleteJamTrack: (state, action) => { + const { id } = action.payload; + state.jamTracks = state.jamTracks.filter(jamTrack => jamTrack.id !== id); + } + }, + extraReducers: builder => { + builder + .addCase(fetchMyJamTracks.pending, (state, action) => { + state.status = 'loading'; + }) + .addCase(fetchMyJamTracks.fulfilled, (state, action) => { + state.status = 'succeeded'; + state.jamTracks = action.payload.jamtracks; + + //--- amend the state to include only unique jamTracks + // const records = new Set([...state.jamTracks, ...action.payload.jamtracks]); + // const unique = []; + // records.map(x => (unique.filter(a => a.id === x.id).length > 0 ? null : unique.push(x))); + // state.jamTracks = unique; + // state.next = action.payload.next; + // state.status = 'succeeded'; + //--- + }) + .addCase(fetchMyJamTracks.rejected, (state, action) => { + state.status = 'failed'; + state.error = action.error.message; + }); + } +}); + +export const { addJamTrack, deleteJamTrack } = myJamTracksSlice.actions; +export default myJamTracksSlice.reducer; diff --git a/jam-ui/src/store/store.js b/jam-ui/src/store/store.js index b5d49dd1f..fec3b7ad5 100644 --- a/jam-ui/src/store/store.js +++ b/jam-ui/src/store/store.js @@ -8,6 +8,8 @@ import notificationReducer from './features/notificationSlice' import latencyReducer from "./features/latencySlice" import friendReducer from "./features/friendsSlice" import sessionsHistoryReducer from "./features/sessionsHistorySlice" +import myJamTracksSlice from "./features/myJamTracksSlice" +import jamTrackSlice from "./features/jamTrackSlice" export default configureStore({ reducer: { @@ -20,5 +22,7 @@ export default configureStore({ lobbyChat: lobbyChatMessagesReducer, friend: friendReducer, sessionsHistory: sessionsHistoryReducer, // this is the slice that holds the sessions history + myJamTrack: myJamTracksSlice, + jamTrack: jamTrackSlice } }) \ No newline at end of file
MixActionsActions
Full JamTrack - + + + +
{mix.name} - - + + {mix.id === 'temp' ? ( + + ) : ( + <> + downloadMix(mix.id)} style={{ cursor: 'pointer' }}> + + + deleteMix(mix.id)} + disabled={deleteMixdownStatus === 'loading'} + style={{ cursor: 'pointer' }} + > + + + + )}