fixes related to beta site profile edit and lobby page

This commit is contained in:
Nuwan 2024-02-19 19:00:53 +05:30
parent 4c161025e8
commit 8cf7048b7f
8 changed files with 159 additions and 80 deletions

View File

@ -1,16 +0,0 @@
import React, {useEffect} from "react";
import { useAuth } from '../../context/UserAuth';
import avatar from "../../assets/img/team/avatar.png";
const JKCurrentUserAvatar = () => {
const { currentUser } = useAuth();
if(currentUser && currentUser.photo_url) {
return ( <img className="avatar avatar-xl rounded-circle mr-1" src={currentUser.photo_url} /> );
}else {
return ( <img className="avatar avatar-xl rounded-circle mr-1" src={avatar} /> );
}
}
export default JKCurrentUserAvatar;

View File

@ -3,7 +3,7 @@ import { Card, CardBody, Col, Row, CardHeader, Form, FormGroup, Label, Input, Bu
import Select from 'react-select';
import FalconCardHeader from '../common/FalconCardHeader';
import { useTranslation } from 'react-i18next';
import JKCurrentUserAvatar from '../navbar/JKCurrentUserAvatar';
import JKProfileAvatar from '../profile/JKProfileAvatar';
import { useAuth } from '../../context/UserAuth';
import { useForm, Controller } from 'react-hook-form';
import {
@ -15,7 +15,7 @@ import {
getRegions,
getCities
} from '../../helpers/rest';
import JKModalDialog from '../common/JKModalDialog';
import JKProfileAvatarUpload from '../profile/JKProfileAvatarUpload';
function JKEditProfile() {
const { t } = useTranslation('profile');
@ -28,7 +28,8 @@ function JKEditProfile() {
const [countries, setCountries] = useState([]);
const [regions, setRegions] = useState([]);
const [cities, setCities] = useState([]);
const [showPhotoModal, setShowPhotoModal] = useState(false);
const [showAvatarUpload, setShowAvatarUpload] = useState(false);
//const [userData, setUserData] = useState({});
const [_, forceUpdate] = useReducer(x => x + 1, 0);
@ -64,6 +65,7 @@ function JKEditProfile() {
setCurrentUserLoaded(true);
fetchCurentUser().then(data => {
console.log("userData", data)
//setUserData(data);
updateUserData(data);
fetchInstruments();
fetchGenres();
@ -370,8 +372,8 @@ function JKEditProfile() {
.catch(error => console.log(error));
};
const togglePhotoModel = () => {
setShowPhotoModal(!showPhotoModal);
const toggleAvatarUpload = () => {
setShowAvatarUpload(!showAvatarUpload);
};
return (
@ -427,14 +429,14 @@ function JKEditProfile() {
<Col md={4}>
<div className="d-flex align-items-center">
<div>
<JKCurrentUserAvatar size="sm" />
<JKProfileAvatar src={currentUser.photo_url} size="s" />
</div>
<div>
<a
href="#"
onClick={e => {
e.preventDefault();
togglePhotoModel();
toggleAvatarUpload();
}}
>
{t('change_photo')}
@ -693,27 +695,7 @@ function JKEditProfile() {
</Form>
</CardBody>
</Card>
<JKModalDialog
show={showPhotoModal}
onToggle={togglePhotoModel}
title={t('lobby.chat_notifications.title', { ns: 'sessions' })}
showFooter={false}
>
<div className='d-flex flex-column'>
<div className='d-flex justify-content-center'>
<JKCurrentUserAvatar size="xl" />
</div>
<div className="d-flex justify-content-center">
<Button color="secondary" outline className="ml-2" onClick={() => {}}>
{t('photo_modal.upload', { ns: 'profile' })}
</Button>
<Button color="secondary" outline className="ml-2" onClick={() => {}}>
{t('photo_modal.delete', { ns: 'profile' })}
</Button>
</div>
</div>
</JKModalDialog>
<JKProfileAvatarUpload show={showAvatarUpload} toggle={toggleAvatarUpload} />
</>
);
}

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useLayoutEffect, useState } from 'react';
import { Col, Row, Card, CardBody, Button, CardHeader, Nav, NavItem, NavLink, TabContent, TabPane } from 'reactstrap';
import { useTranslation } from 'react-i18next';
import { useResponsive } from '@farfetch/react-context-responsive';
@ -18,6 +18,7 @@ import JKTooltip from '../common/JKTooltip';
import { updateUser } from '../../helpers/rest';
import { postUserAppInteraction } from '../../helpers/rest';
import { useVisbilityState } from '../../hooks/useVisibilityState';
import { useHistory } from 'react-router-dom'
function JKMusicSessionsLobby() {
const INTERACTION_CLIENT = 'browser';
@ -31,6 +32,7 @@ function JKMusicSessionsLobby() {
const { currentUser } = useAuth();
const isNativeAppAvailable = useNativeAppCheck();
const { nativeAppUnavailable, setNativeAppUnavailable } = useNativeApp();
const history = useHistory();
const onlineMusicians = useSelector(state => state.onlineMusician.musicians);
const loadingStatus = useSelector(state => state.onlineMusician.status);
@ -39,7 +41,10 @@ function JKMusicSessionsLobby() {
const [submitted, setSubmitted] = useState(false);
const [activeTab, setActiveTab] = useState('1');
const [showNotificationsModal, setShowNotificationsModal] = useState(false);
const NOTIFICATION_INTERVAL = 1000 * 10 //10 seconds
const NOTIFICATION_MODAL_INTERVAL = 1000 * 10 //10 seconds
const MUSICIANS_FETCH_INTERVAL = 1000 * 20 //20 seconds
const LIVENESS_UPDATE_INTERVAL = 1000 * 60 * 1 //1 minute
const documentVisibility = useVisbilityState();
@ -54,13 +59,21 @@ function JKMusicSessionsLobby() {
} else {
setTimeout(() => {
setShowNotificationsModal(true);
}, NOTIFICATION_INTERVAL);
}, NOTIFICATION_MODAL_INTERVAL);
}
} catch (error) {
console.log('Error reading localStorage', error);
}
}, []);
//periodically fetch online musicians
useEffect(() => {
const interval = setInterval(() => {
dispatch(fetchOnlineMusicians());
}, MUSICIANS_FETCH_INTERVAL);
return () => clearInterval(interval);
}, []);
useEffect(() => {
if (loadingStatus === 'succeeded' && onlineMusicians.length > 0) {
const userIds = onlineMusicians.map(p => p.id);
@ -69,12 +82,39 @@ function JKMusicSessionsLobby() {
}
}, [loadingStatus]);
//update user liveness when user switches tabs
useEffect(() => {
if(currentUser){
postInteraction(documentVisibility);
}
}, [documentVisibility]);
//update user liveness when user leaves the page
useEffect(() => {
const unlisten = history.listen(() => {
console.log('User is leaving the page');
// Do something before the user leaves the page
postInteraction('hidden');
});
return () => {
console.log('Component is unmounting');
unlisten();
// Do something before the component unmounts
};
}, [history]);
//periodically update user liveness
useEffect(() => {
const interval = setInterval(() => {
if(documentVisibility === 'visible'){
postInteraction('visible');
}
}, LIVENESS_UPDATE_INTERVAL);
return () => clearInterval(interval);
}, [])
const postInteraction = visibilityState => {
const options = {
@ -208,7 +248,6 @@ function JKMusicSessionsLobby() {
<Col>
<div className="table-responsive-xl px-2">
<JKLobbyUserList
loadingStatus={loadingStatus}
onlineMusicians={onlineMusicians}
setSelectedUsers={setSelectedUsers}
/>

View File

@ -0,0 +1,58 @@
import React, { useEffect } from 'react'
import * as filestack from 'filestack-js';
import { Button } from 'reactstrap';
import { useTranslation } from 'react-i18next';
import JKModalDialog from '../common/JKModalDialog';
import JKProfileAvatar from './JKProfileAvatar';
import { useAuth } from '../../context/UserAuth';
import { getUserDetails } from '../../helpers/rest';
const JKProfileAvatarUpload = ({show, toggle}) => {
const { t } = useTranslation('profile');
const { currentUser } = useAuth();
useEffect(() => {
if(currentUser) {
console.log(currentUser.photo_url);
getUserDetails(currentUser.id).then(response => {
console.log('_userDetails', response);
});
}
}, [currentUser]);
const openFilePicker = () => {
const client = filestack.init(window.gon.fp_apikey);
client.picker({
accept: 'image/*',
maxFiles: 1,
onFileUploadFinished: (response) => {
console.log(response);
}
}).open();
}
return (
<JKModalDialog
show={show}
onToggle={toggle}
title={t('lobby.chat_notifications.title', { ns: 'sessions' })}
showFooter={true}
>
<div className='d-flex flex-column'>
<div className='d-flex justify-content-center'>
<JKProfileAvatar src={currentUser.photo_url} size="5xl" />
</div>
<div className="d-flex justify-content-center">
<Button color="secondary" outline className="ml-2" onClick={openFilePicker}>
{t('photo_modal.upload', { ns: 'profile' })}
</Button>
<Button color="secondary" outline className="ml-2" onClick={() => {}}>
{t('photo_modal.delete', { ns: 'profile' })}
</Button>
</div>
</div>
</JKModalDialog>
)
}
export default JKProfileAvatarUpload

View File

@ -3,38 +3,35 @@ import { Table } from 'reactstrap';
import { useTranslation } from 'react-i18next';
import JKLobbyUser from './JKLobbyUser';
import { isIterableArray } from '../../helpers/utils';
import Loader from '../common/Loader';
function JKLobbyUserList({ loadingStatus, onlineMusicians, selectedUsers, setSelectedUsers }) {
function JKLobbyUserList({ onlineMusicians, selectedUsers, setSelectedUsers }) {
const { t } = useTranslation('sessions');
return (
<>
{loadingStatus === 'loading' && onlineMusicians.length === 0 ? (
<Loader />
) : (
<Table striped bordered className="fs--1" data-testid="sessionsLobbyUsersTable">
<thead className="bg-200 text-900">
<Table striped bordered className="fs--1" data-testid="sessionsLobbyUsersTable">
<thead className="bg-200 text-900">
<tr>
<th width="75%" scope="col">
{t('lobby.users.header.musician', { ns: 'sessions' })}
</th>
<th scope="col" className="text-center">
{t('lobby.users.header.actions', { ns: 'sessions' })}
</th>
</tr>
</thead>
<tbody className="list">
{isIterableArray(onlineMusicians) ? (
onlineMusicians.map(musician => (
<JKLobbyUser key={musician.id} user={musician} setSelectedUsers={setSelectedUsers} />
))
) : (
<tr>
<th width="75%" scope="col">
{t('lobby.users.header.musician', { ns: 'sessions' })}
</th>
<th scope="col" className="text-center">
{t('lobby.users.header.actions', { ns: 'sessions' })}
</th>
<td colSpan={2}>{t('lobby.users.not_found')}</td>
</tr>
</thead>
<tbody className="list">
{isIterableArray(onlineMusicians) ? (
onlineMusicians.map(musician => <JKLobbyUser key={musician.id} user={musician} setSelectedUsers={setSelectedUsers} />)
) : (
<tr>
<td colSpan={2}>{t('lobby.users.not_found')}</td>
</tr>
)}
</tbody>
</Table>
)}
)}
</tbody>
</Table>
</>
);
}

View File

@ -24,6 +24,15 @@ export const getPersonById = id => {
);
};
export const getUserDetails = options => {
const { id, ...rest } = options;
return new Promise((resolve, reject) =>
apiFetch(`/users/${id}?${new URLSearchParams(rest)}`)
.then(response => resolve(response))
.catch(error => reject(error))
);
}
export const getPeople = ({ data, offset, limit } = {}) => {
return new Promise((resolve, reject) => {
apiFetch(`/filter?offset=${offset}&limit=${limit}`, {

View File

@ -36,6 +36,12 @@ export const onlineMusiciansSlice = createSlice({
console.log('fetchOnlineMusicians.fulfilled', action.payload)
state.status = 'succeeded'
state.musicians = action.payload
// if (action.payload && action.payload.length > 0) {
// const difference = state.musicians.filter((element) => !action.payload.includes(element));
// if (difference.length > 0) {
// state.musicians = action.payload
// }
// }
})
.addCase(fetchOnlineMusicians.rejected, (state, action) => {
state.status = 'failed'

View File

@ -317,18 +317,22 @@ module JamRuby
#the users that have opened the lobby page but now in a different tab or window or
#the users that have been active in the last 15 minutes
query = User.joins(:app_interactions).where("
(app_interactions.client = 'browser' AND app_interactions.action_at > ? AND app_interactions.screen = 'lobby' AND app_interactions.action = 'page:enter' AND app_interactions.user_id <> ?)
OR (app_interactions.client = 'browser' AND app_interactions.action_at > ? AND app_interactions.screen = 'lobby' AND app_interactions.action = 'page:exit' AND app_interactions.user_id = ? AND users.accept_desktop_notifications = ?)
OR (users.last_jam_updated_at IS NOT NULL AND users.last_jam_updated_at > ? AND users.id <> ?)",
10.minutes.ago,
(app_interactions.client = 'browser' AND app_interactions.action_at > ? AND app_interactions.screen = 'session:lobby' AND app_interactions.action = 'page:enter' AND app_interactions.user_id <> ?)
OR (app_interactions.client = 'browser' AND app_interactions.action_at > ? AND app_interactions.screen = 'session:lobby' AND app_interactions.action = 'page:exit' AND app_interactions.user_id <> ? AND users.accept_desktop_notifications = ?)
OR (users.last_jam_updated_at IS NOT NULL AND users.last_jam_updated_at > ? AND users.id <> ? AND users.accept_desktop_notifications = ?)
",
5.minutes.ago,
current_user.id,
10.minutes.ago,
5.minutes.ago,
current_user.id,
true,
10.minutes.ago,
current_user.id
5.minutes.ago,
current_user.id,
true
)
#
#the users that are currently not in a music session
live_music_sessions = ActiveMusicSession
if live_music_sessions.count > 0