session history page:
list all the sessions in decending order they were created
This commit is contained in:
parent
7176fecd7b
commit
97e0a8d36a
|
|
@ -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 (
|
||||
<Card>
|
||||
<FalconCardHeader title={t('history.page_title', { ns: 'sessions' })} titleClass="font-weight-bold" />
|
||||
<CardBody className="pt-0">
|
||||
<CardBody className="pt-0 pr-0">
|
||||
{loadingStatus === 'loading' && sessions.length === 0 ? (
|
||||
<Loader />
|
||||
) : isIterableArray(sessions) ? (
|
||||
|
|
@ -42,7 +43,7 @@ const JKMusicSessionsHistory = () => {
|
|||
</Row>
|
||||
) : (
|
||||
<Row className="swiper-container d-block d-md-none" data-testid="sessionsSwiper">
|
||||
{/* <JKSessionSwiper sessions={sessions} /> */}
|
||||
<JKSessionsHistorySwiper sessions={sessions} />
|
||||
</Row>
|
||||
)}
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@ const JKProfileSidePanel = props => {
|
|||
{currentUser && (
|
||||
<div className="p-3 bg-white border-top fixed-bottom">
|
||||
<JKConnectButton
|
||||
cssClasses="mb-2 mb-md-0"
|
||||
currentUser={currentUser}
|
||||
user={user}
|
||||
addContent={
|
||||
|
|
|
|||
|
|
@ -17,12 +17,15 @@ import { useNativeApp } from '../../context/NativeAppContext';
|
|||
import EnterIcon from '../../icons/enter.svg';
|
||||
import JKInstrumentIcon from '../profile/JKInstrumentIcon';
|
||||
|
||||
import useSessionHelper from './JKUseSessionHelper';
|
||||
|
||||
function JKSession({ session }) {
|
||||
const { currentUser } = useAuth();
|
||||
const dispatch = useDispatch();
|
||||
const { t } = useTranslation();
|
||||
const { greaterThan } = useResponsive();
|
||||
const { setNativeAppUnavailable } = useNativeApp();
|
||||
const { sessionDescription } = useSessionHelper(session);
|
||||
|
||||
useEffect(() => {
|
||||
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 }) {
|
|||
<small>{hasFriendNote(session)}</small>
|
||||
</u>
|
||||
</div>
|
||||
<div>{sessionDescription(session)}</div>
|
||||
<div>{sessionDescription}</div>
|
||||
</td>
|
||||
<td>
|
||||
{session.participants.map(participant => (
|
||||
|
|
|
|||
|
|
@ -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 ? (
|
||||
<tr key={session_id}>
|
||||
<td>
|
||||
<div>
|
||||
<u>
|
||||
<small>{sessionDateTime}</small>
|
||||
</u>
|
||||
</div>
|
||||
<div>{sessionDescription}</div>
|
||||
</td>
|
||||
<td>
|
||||
{participants.map(participant => (
|
||||
<Row style={musicianRowStyle} key={participant.id}>
|
||||
<Col>
|
||||
<JKSessionUser user={participant.user} />
|
||||
</Col>
|
||||
</Row>
|
||||
))}
|
||||
</td>
|
||||
<td className="text-center">
|
||||
{participants.map(participant => (
|
||||
<Row key={participant.id} style={musicianRowStyle}>
|
||||
<Col>
|
||||
<JKUserLatencyBadge key={participant.id} user={participant.user} showBadgeOnly={true} />
|
||||
</Col>
|
||||
</Row>
|
||||
))}
|
||||
</td>
|
||||
<td>
|
||||
{participants.map(participant => (
|
||||
<Row style={musicianRowStyle} key={participant.id} data-testid={`Participant${participant.id}Tracks`}>
|
||||
<Col>
|
||||
{participant.tracks.map(track => (
|
||||
<span key={track.id} className="mr-1 mb-1" title={track.instrment}>
|
||||
<a
|
||||
id={`Participant${participant.id}Track${track.id}Instrument`}
|
||||
data-testid={`Track${track.id}Instrument`}
|
||||
>
|
||||
<JKInstrumentIcon instrumentId={track.instrument_id} instrumentName={track.instrument} />
|
||||
</a>
|
||||
<UncontrolledTooltip
|
||||
placement="top"
|
||||
target={`Participant${participant.id}Track${track.id}Instrument`}
|
||||
>
|
||||
{track.instrument}
|
||||
</UncontrolledTooltip>
|
||||
</span>
|
||||
))}
|
||||
</Col>
|
||||
</Row>
|
||||
))}
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
<Row>
|
||||
<Col>
|
||||
<div>
|
||||
<u>
|
||||
<small>{sessionDateTime}</small>
|
||||
</u>
|
||||
</div>
|
||||
<div>{sessionDescription}</div>
|
||||
<div className="d-flex flex-row justify-content-between mt-3">
|
||||
<div className="ml-0 ms-2">
|
||||
<h5>{t('list.header.musicians', { ns: 'sessions' })}</h5>
|
||||
</div>
|
||||
<div className="ml-2 ms-2">
|
||||
<strong>{t('list.header.latency', { ns: 'sessions' })}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{participants.map(participant => (
|
||||
<JKSessionUser user={participant.user} />
|
||||
))}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default JKSessionsHistoryItem;
|
||||
|
|
@ -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 (
|
||||
<div>
|
||||
<h1>JKSessionsHistoryList</h1>
|
||||
<pre>{JSON.stringify(sessions, null, 2)}</pre>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<>
|
||||
<Table striped bordered className="fs--1">
|
||||
<thead className="bg-200 text-900">
|
||||
<tr>
|
||||
<th width="35%" scope="col">
|
||||
{t('list.header.session', { ns: 'sessions' })}
|
||||
</th>
|
||||
<th width="15%" scope="col" style={{ minWidth: 250 }}>
|
||||
{t('list.header.musicians', { ns: 'sessions' })}
|
||||
</th>
|
||||
<th scope="col" className="text-center">
|
||||
{t('list.header.latency', { ns: 'sessions' })}
|
||||
</th>
|
||||
<th scope="col">{t('list.header.instruments', { ns: 'sessions' })}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{Object.entries(sessionsById).map(([session_id, sessionGroup]) => (
|
||||
<JKSessionsHistoryItem key={session_id} session_id={session_id} sessionGroup={sessionGroup} />
|
||||
))}
|
||||
</tbody>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default JKSessionsHistoryList
|
||||
export default JKSessionsHistoryList;
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<>
|
||||
<Swiper
|
||||
spaceBetween={0}
|
||||
slidesPerView={1}
|
||||
//onSlideChange={() => console.log('slide change')}
|
||||
onSlideNextTransitionEnd={swiper => {
|
||||
if(swiper.isEnd){
|
||||
//goNextPage()
|
||||
}
|
||||
}}
|
||||
pagination={{
|
||||
clickable: true,
|
||||
type: 'custom'
|
||||
}}
|
||||
navigation={{
|
||||
nextEl: '.swiper-button-next',
|
||||
prevEl: '.swiper-button-prev'
|
||||
}}
|
||||
>
|
||||
{Object.entries(sessionsById).map(([session_id, sessionGroup]) => (
|
||||
<SwiperSlide key={`sessions-swiper-item-${session_id}`}>
|
||||
<Card className="swiper-card">
|
||||
<CardHeader className="text-center bg-200">
|
||||
<h4 className="d-inline-block align-center mt-1">{t("history.header.session", {ns: 'sessions'})}</h4>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<JKSessionsHistoryItem key={session_id} session_id={session_id} sessionGroup={sessionGroup} />
|
||||
</CardBody>
|
||||
</Card>
|
||||
</SwiperSlide>
|
||||
))}
|
||||
</Swiper>
|
||||
<div className="py-4 px-6 bg-white border-top w-100 fixed-bottom">
|
||||
<div className="swiper-pagination" />
|
||||
<div className="swiper-button-prev" />
|
||||
<div className="swiper-button-next" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
JKSessionsHistorySwiper.propTypes = {
|
||||
sessions: PropTypes.arrayOf(PropTypes.instanceOf(Object)).isRequired,
|
||||
};
|
||||
|
||||
export default JKSessionsHistorySwiper;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
export const groupByKey = (list, key) => list.reduce((hash, obj) => ({...hash, [obj[key]]:( hash[obj[key]] || [] ).concat(obj)}), {})
|
||||
|
|
@ -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'
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue