From 97e0a8d36a1d724caac12d441c42ead729dbb1a2 Mon Sep 17 00:00:00 2001 From: Nuwan Date: Sun, 5 May 2024 18:38:29 +0530 Subject: [PATCH] session history page: list all the sessions in decending order they were created --- .../components/page/JKMusicSessionsHistory.js | 5 +- .../components/profile/JKProfileSidePanel.js | 1 + jam-ui/src/components/sessions/JKSession.js | 27 ++-- .../sessions/JKSessionsHistoryItem.js | 138 ++++++++++++++++++ .../sessions/JKSessionsHistoryList.js | 46 ++++-- .../sessions/JKSessionsHistorySwiper.js | 73 +++++++++ .../components/sessions/JKUseSessionHelper.js | 23 +++ jam-ui/src/helpers/utils.js | 4 +- .../store/features/sessionsHistorySlice.js | 5 +- ruby/lib/jam_ruby/models/music_session.rb | 13 +- .../api_music_sessions/list_history.rabl | 3 +- 11 files changed, 308 insertions(+), 30 deletions(-) create mode 100644 jam-ui/src/components/sessions/JKSessionsHistoryItem.js create mode 100644 jam-ui/src/components/sessions/JKSessionsHistorySwiper.js create mode 100644 jam-ui/src/components/sessions/JKUseSessionHelper.js diff --git a/jam-ui/src/components/page/JKMusicSessionsHistory.js b/jam-ui/src/components/page/JKMusicSessionsHistory.js index 34fc6705b..6bb972889 100644 --- a/jam-ui/src/components/page/JKMusicSessionsHistory.js +++ b/jam-ui/src/components/page/JKMusicSessionsHistory.js @@ -8,6 +8,7 @@ import { isIterableArray } from '../../helpers/utils'; import { useResponsive } from '@farfetch/react-context-responsive'; import { fetchSessionsHistory } from '../../store/features/sessionsHistorySlice'; import JKSessionsHistoryList from '../sessions/JKSessionsHistoryList'; +import JKSessionsHistorySwiper from '../sessions/JKSessionsHistorySwiper'; const JKMusicSessionsHistory = () => { const { t } = useTranslation(); @@ -29,7 +30,7 @@ const JKMusicSessionsHistory = () => { return ( - + {loadingStatus === 'loading' && sessions.length === 0 ? ( ) : isIterableArray(sessions) ? ( @@ -42,7 +43,7 @@ const JKMusicSessionsHistory = () => { ) : ( - {/* */} + )} diff --git a/jam-ui/src/components/profile/JKProfileSidePanel.js b/jam-ui/src/components/profile/JKProfileSidePanel.js index 11686c311..843a9c6e2 100644 --- a/jam-ui/src/components/profile/JKProfileSidePanel.js +++ b/jam-ui/src/components/profile/JKProfileSidePanel.js @@ -155,6 +155,7 @@ const JKProfileSidePanel = props => { {currentUser && (
{ const otherUserIds = session.participants.map(p => p.user.id); @@ -30,17 +33,17 @@ function JKSession({ session }) { dispatch(fetchUserLatencies(options)); }, [session.id]); - const sessionDescription = session => { - if (session.description) { - return session.description; - } else if (session.musician_access && !session.approval_required) { - return t('list.descriptions.public_open_session', { ns: 'sessions' }); - } else if (session.musician_access && session.approval_required) { - return t('list.descriptions.private_session', { ns: 'sessions' }); - } else if (!session.musician_access && !session.approval_required) { - return t('list.descriptions.rsvp_session', { ns: 'sessions' }); - } - }; + // const sessionDescription = session => { + // if (session.description) { + // return session.description; + // } else if (session.musician_access && !session.approval_required) { + // return t('list.descriptions.public_open_session', { ns: 'sessions' }); + // } else if (session.musician_access && session.approval_required) { + // return t('list.descriptions.private_session', { ns: 'sessions' }); + // } else if (!session.musician_access && !session.approval_required) { + // return t('list.descriptions.rsvp_session', { ns: 'sessions' }); + // } + // }; const invitedNote = session => { if (session.invitations.find(i => i.receiver_id === currentUser.id)) { @@ -78,7 +81,7 @@ function JKSession({ session }) { {hasFriendNote(session)}
-
{sessionDescription(session)}
+
{sessionDescription}
{session.participants.map(participant => ( diff --git a/jam-ui/src/components/sessions/JKSessionsHistoryItem.js b/jam-ui/src/components/sessions/JKSessionsHistoryItem.js new file mode 100644 index 000000000..aa885dd5f --- /dev/null +++ b/jam-ui/src/components/sessions/JKSessionsHistoryItem.js @@ -0,0 +1,138 @@ +import React, { useState, useEffect } from 'react'; +import { useResponsive } from '@farfetch/react-context-responsive'; +import useSessionHelper from './JKUseSessionHelper'; +import { Row, Col, UncontrolledTooltip } from 'reactstrap'; +import JKInstrumentIcon from '../profile/JKInstrumentIcon'; +import JKSessionUser from './JKSessionUser'; +import JKUserLatencyBadge from '../profile/JKUserLatencyBadge'; +import { useTranslation } from 'react-i18next'; + +const JKSessionsHistoryItem = ({ session_id, sessionGroup }) => { + const { greaterThan } = useResponsive(); + const { sessionDescription, sessionDateTime } = useSessionHelper(sessionGroup[0]); + const [participants, setParticipants] = useState([]); + const { t } = useTranslation(); + + useEffect(() => { + setParticipants( + sessionGroup.map(history => ({ + id: history.user_id, + user: { + id: history.user_id, + photo_url: history.photo_url, + first_name: history.first_name, + last_name: history.last_name, + name: `${history.first_name} ${history.last_name}` + }, + tracks: history.instruments.split('|').map((instrument, index) => ({ + id: index, + instrument_id: instrument, + instrument: instrument + })) + })) + ); + }, [sessionGroup]); + + // const formattedDate = date => { + // const d = new Date(date); + // return d.toLocaleDateString('en-us', { + // weekday: 'long', + // year: 'numeric', + // month: 'short', + // day: 'numeric', + // timeZoneName: 'short' + // }); + // }; + + const musicianRowStyle = { + height: '40px', + flexWrap: 'wrap', + overflow: 'hidden', + alignItems: 'center' + }; + + return ( + <> + {greaterThan.sm ? ( + + +
+ + {sessionDateTime} + +
+
{sessionDescription}
+ + + {participants.map(participant => ( + + + + + + ))} + + + {participants.map(participant => ( + + + + + + ))} + + + {participants.map(participant => ( + + + {participant.tracks.map(track => ( + + + + + + {track.instrument} + + + ))} + + + ))} + + + ) : ( + + +
+ + {sessionDateTime} + +
+
{sessionDescription}
+
+
+
{t('list.header.musicians', { ns: 'sessions' })}
+
+
+ {t('list.header.latency', { ns: 'sessions' })} +
+
+
+ {participants.map(participant => ( + + ))} +
+ +
+ )} + + ); +}; + +export default JKSessionsHistoryItem; diff --git a/jam-ui/src/components/sessions/JKSessionsHistoryList.js b/jam-ui/src/components/sessions/JKSessionsHistoryList.js index f95913f74..7e8d18a8e 100644 --- a/jam-ui/src/components/sessions/JKSessionsHistoryList.js +++ b/jam-ui/src/components/sessions/JKSessionsHistoryList.js @@ -1,12 +1,40 @@ -import React from 'react' +import React from 'react'; +import { groupByKey } from '../../helpers/utils'; +import { Table } from 'reactstrap'; +import { useResponsive } from '@farfetch/react-context-responsive'; +import JKSessionsHistoryItem from './JKSessionsHistoryItem'; +import { useTranslation } from 'react-i18next'; + +const JKSessionsHistoryList = ({ sessions }) => { + const { greaterThan } = useResponsive(); + const sessionsById = groupByKey(sessions, 'session_id'); + const { t } = useTranslation(); -const JKSessionsHistoryList = ({sessions}) => { return ( -
-

JKSessionsHistoryList

-
{JSON.stringify(sessions, null, 2)}
-
- ) -} + <> + + + + + + + + + + + {Object.entries(sessionsById).map(([session_id, sessionGroup]) => ( + + ))} + +
+ {t('list.header.session', { ns: 'sessions' })} + + {t('list.header.musicians', { ns: 'sessions' })} + + {t('list.header.latency', { ns: 'sessions' })} + {t('list.header.instruments', { ns: 'sessions' })}
+ + ); +}; -export default JKSessionsHistoryList \ No newline at end of file +export default JKSessionsHistoryList; diff --git a/jam-ui/src/components/sessions/JKSessionsHistorySwiper.js b/jam-ui/src/components/sessions/JKSessionsHistorySwiper.js new file mode 100644 index 000000000..2f843ee24 --- /dev/null +++ b/jam-ui/src/components/sessions/JKSessionsHistorySwiper.js @@ -0,0 +1,73 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { groupByKey } from '../../helpers/utils'; +import JKSessionsHistoryItem from './JKSessionsHistoryItem'; +import { useTranslation } from 'react-i18next'; + +// import Swiper core and required modules +import SwiperCore, { Navigation, Pagination, Scrollbar, A11y } from 'swiper'; + +// Import Swiper React components +import { Swiper, SwiperSlide } from 'swiper/react'; + +// Import Swiper styles +import 'swiper/swiper.scss'; +import 'swiper/components/navigation/navigation.scss'; +import 'swiper/components/pagination/pagination.scss'; +import 'swiper/components/scrollbar/scrollbar.scss'; + +import { Card, CardBody, CardHeader } from 'reactstrap'; + +SwiperCore.use([Navigation, Pagination, Scrollbar, A11y]); + +const JKSessionsHistorySwiper = ({ sessions }) => { + const sessionsById = groupByKey(sessions, 'session_id'); + const { t } = useTranslation(); + + return ( + <> + console.log('slide change')} + onSlideNextTransitionEnd={swiper => { + if(swiper.isEnd){ + //goNextPage() + } + }} + pagination={{ + clickable: true, + type: 'custom' + }} + navigation={{ + nextEl: '.swiper-button-next', + prevEl: '.swiper-button-prev' + }} + > + {Object.entries(sessionsById).map(([session_id, sessionGroup]) => ( + + + +

{t("history.header.session", {ns: 'sessions'})}

+
+ + + +
+
+ ))} +
+
+
+
+
+
+ + ); +}; + +JKSessionsHistorySwiper.propTypes = { + sessions: PropTypes.arrayOf(PropTypes.instanceOf(Object)).isRequired, +}; + +export default JKSessionsHistorySwiper; diff --git a/jam-ui/src/components/sessions/JKUseSessionHelper.js b/jam-ui/src/components/sessions/JKUseSessionHelper.js new file mode 100644 index 000000000..63a7103f1 --- /dev/null +++ b/jam-ui/src/components/sessions/JKUseSessionHelper.js @@ -0,0 +1,23 @@ +import { useTranslation } from 'react-i18next'; + +const useSessionHelper = (session) => { + const { t } = useTranslation(); + + const sessionDescription = session => { + if (session.description) { + return session.description; + } else if (session.musician_access && !session.approval_required) { + return t('list.descriptions.public_open_session', { ns: 'sessions' }); + } else if (session.musician_access && session.approval_required) { + return t('list.descriptions.private_session', { ns: 'sessions' }); + } else if (!session.musician_access && !session.approval_required) { + return t('list.descriptions.rsvp_session', { ns: 'sessions' }); + } + }; + + return { + sessionDescription: sessionDescription(session) + }; +}; + +export default useSessionHelper; \ No newline at end of file diff --git a/jam-ui/src/helpers/utils.js b/jam-ui/src/helpers/utils.js index d795eb38e..222fd1774 100644 --- a/jam-ui/src/helpers/utils.js +++ b/jam-ui/src/helpers/utils.js @@ -246,4 +246,6 @@ const months = new Array("January", "February", "March", export const formatDateShort = (dateString) => { const date = dateString instanceof Date ? dateString : new Date(dateString); return months[date.getMonth()] + ' ' + date.getDate() + ', ' + date.getFullYear(); -} \ No newline at end of file +} + +export const groupByKey = (list, key) => list.reduce((hash, obj) => ({...hash, [obj[key]]:( hash[obj[key]] || [] ).concat(obj)}), {}) \ No newline at end of file diff --git a/jam-ui/src/store/features/sessionsHistorySlice.js b/jam-ui/src/store/features/sessionsHistorySlice.js index 09bff6f34..252737caa 100644 --- a/jam-ui/src/store/features/sessionsHistorySlice.js +++ b/jam-ui/src/store/features/sessionsHistorySlice.js @@ -27,12 +27,9 @@ export const SessionsHistorySlice = createSlice({ }) .addCase(fetchSessionsHistory.fulfilled, (state, action) => { console.log(action.payload); - // state.status = "succeeded"; - // state.sessions = action.payload; - const records = new Set([...state.sessions, ...action.payload]); const unique = []; - records.map(x => unique.filter(a => a.id === x.id).length > 0 ? null : unique.push(x)) + records.map(x => unique.filter(a => a.session_history_id === x.session_history_id).length > 0 ? null : unique.push(x)) state.sessions = unique state.status = 'succeeded' }) diff --git a/ruby/lib/jam_ruby/models/music_session.rb b/ruby/lib/jam_ruby/models/music_session.rb index 748f6b517..9baf5175f 100644 --- a/ruby/lib/jam_ruby/models/music_session.rb +++ b/ruby/lib/jam_ruby/models/music_session.rb @@ -571,7 +571,18 @@ module JamRuby def self.history(options) offset = options[:offset] || 0 limit = options[:limit] || 10 - MusicSession.order('created_at DESC').offset(offset).limit(limit) + MusicSession.joins( + %Q{ + INNER JOIN + music_sessions_user_history + ON + music_sessions.id = music_sessions_user_history.music_session_id + INNER JOIN + users + ON + music_sessions_user_history.user_id = users.id + } + ).order('music_sessions.created_at DESC').select("music_sessions.id AS session_id, music_sessions_user_history.id AS session_history_id, music_sessions.created_at, music_sessions.name, music_sessions.description, music_sessions_user_history.instruments, users.first_name, users.last_name, users.photo_url, users.id AS user_id").offset(offset).limit(limit) end def self.scheduled user, only_public = false diff --git a/web/app/views/api_music_sessions/list_history.rabl b/web/app/views/api_music_sessions/list_history.rabl index ee0b926ef..8b9500827 100644 --- a/web/app/views/api_music_sessions/list_history.rabl +++ b/web/app/views/api_music_sessions/list_history.rabl @@ -1,3 +1,4 @@ collection @music_sessions -attributes :id, :name, :description, :created_at +attributes :session_id, :session_history_id, :name, :description, :created_at, :musician_access, :approval_required, +:user_id, :instruments, :first_name, :last_name, :photo_url