2020-04-26 11:36:41 +02:00
|
|
|
import React, { useEffect, useState } from 'react';
|
|
|
|
import './App.scss';
|
|
|
|
import RoomRow from './RoomRow';
|
2020-04-26 22:41:06 +02:00
|
|
|
import { SortArrow } from './SortArrow';
|
2020-08-27 17:21:34 +02:00
|
|
|
import { api, Room, Restriction, Access } from '../Common/Api';
|
2020-04-26 11:36:41 +02:00
|
|
|
import NewRoomForm from './NewRoomForm';
|
|
|
|
|
2020-09-08 17:13:21 +02:00
|
|
|
export type SortKey = 'name' | 'welcome' | 'maxParticipants' | 'record' | 'access';
|
2020-04-26 11:36:41 +02:00
|
|
|
|
2020-09-01 09:48:24 +02:00
|
|
|
enum SortOrder { DESC = -1, ASC = 1 }
|
2020-04-26 11:36:41 +02:00
|
|
|
|
|
|
|
function sortRooms(key: SortKey, orderBy: SortOrder) {
|
|
|
|
return (a: Room, b: Room) => {
|
|
|
|
switch (key) {
|
2020-04-27 16:47:32 +02:00
|
|
|
case 'name':
|
|
|
|
case 'welcome':
|
2020-09-08 17:13:21 +02:00
|
|
|
case 'access':
|
2020-04-27 16:47:32 +02:00
|
|
|
return a[key].localeCompare(b[key]) * orderBy;
|
|
|
|
case 'maxParticipants':
|
|
|
|
return (a.maxParticipants - b.maxParticipants) * orderBy;
|
|
|
|
case 'record':
|
|
|
|
if (a.record && !b.record) {
|
|
|
|
return 1 * orderBy;
|
|
|
|
}
|
|
|
|
if (!a.record && b.record) {
|
|
|
|
return -1 * orderBy;
|
|
|
|
}
|
2020-04-26 11:36:41 +02:00
|
|
|
|
2020-04-27 16:47:32 +02:00
|
|
|
return 0;
|
2020-04-26 11:36:41 +02:00
|
|
|
}
|
2020-04-27 16:50:45 +02:00
|
|
|
};
|
2020-04-26 11:36:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type Props = {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const App: React.FC<Props> = () => {
|
2020-09-08 16:59:39 +02:00
|
|
|
const [isLoaded, setLoaded] = useState(false);
|
2020-06-17 10:52:15 +02:00
|
|
|
const [error, setError] = useState<string>('');
|
2020-08-27 17:21:34 +02:00
|
|
|
const [restriction, setRestriction] = useState<Restriction>();
|
2020-04-26 11:36:41 +02:00
|
|
|
const [rooms, setRooms] = useState<Room[]>([]);
|
|
|
|
const [orderBy, setOrderBy] = useState<SortKey>('name');
|
|
|
|
const [sortOrder, setSortOrder] = useState(SortOrder.ASC);
|
|
|
|
|
2020-08-27 17:21:34 +02:00
|
|
|
const rows = rooms.sort(sortRooms(orderBy, sortOrder)).map(room => <RoomRow room={room} restriction={restriction} key={room.id} updateRoom={updateRoom} deleteRoom={deleteRoom} />);
|
2020-04-26 11:36:41 +02:00
|
|
|
|
|
|
|
useEffect(() => {
|
2020-09-08 16:59:39 +02:00
|
|
|
Promise.all([
|
|
|
|
loadRestriction(),
|
|
|
|
loadRooms(),
|
|
|
|
]).catch(() => {
|
|
|
|
setError(t('bbb', 'Server error'));
|
|
|
|
}).then(() => {
|
|
|
|
setLoaded(true);
|
|
|
|
});
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
function loadRestriction() {
|
|
|
|
return api.getRestriction().then(restriction => {
|
2020-08-27 17:21:34 +02:00
|
|
|
setRestriction(restriction);
|
|
|
|
}).catch(err => {
|
|
|
|
console.warn('Could not load restriction', err);
|
2020-09-08 16:59:39 +02:00
|
|
|
|
|
|
|
throw err;
|
2020-08-27 17:21:34 +02:00
|
|
|
});
|
2020-09-08 16:59:39 +02:00
|
|
|
}
|
2020-04-26 11:36:41 +02:00
|
|
|
|
2020-09-08 16:59:39 +02:00
|
|
|
function loadRooms() {
|
|
|
|
return api.getRooms().then(rooms => {
|
2020-04-26 11:36:41 +02:00
|
|
|
setRooms(rooms);
|
2020-06-17 10:52:15 +02:00
|
|
|
}).catch((err) => {
|
|
|
|
console.warn('Could not load rooms', err);
|
|
|
|
|
2020-09-08 16:59:39 +02:00
|
|
|
throw err;
|
2020-04-26 11:36:41 +02:00
|
|
|
});
|
2020-09-08 16:59:39 +02:00
|
|
|
}
|
2020-04-26 11:36:41 +02:00
|
|
|
|
|
|
|
function onOrderBy(key: SortKey) {
|
|
|
|
if (orderBy === key) {
|
|
|
|
setSortOrder(sortOrder === SortOrder.ASC ? SortOrder.DESC : SortOrder.ASC);
|
|
|
|
}
|
|
|
|
|
|
|
|
setOrderBy(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
function addRoom(name: string) {
|
|
|
|
if (!name) {
|
2020-06-04 10:16:09 +02:00
|
|
|
return Promise.resolve();
|
2020-04-26 11:36:41 +02:00
|
|
|
}
|
|
|
|
|
2020-08-27 17:21:34 +02:00
|
|
|
let access = Access.Public;
|
|
|
|
|
|
|
|
const disabledRoomTypes = restriction?.roomTypes || [];
|
|
|
|
if (disabledRoomTypes.length > 0 && disabledRoomTypes.indexOf(access) > -1) {
|
|
|
|
access = Object.values(Access).filter(a => disabledRoomTypes.indexOf(a) < 0)[0] as Access;
|
|
|
|
}
|
|
|
|
|
|
|
|
const maxParticipants = restriction?.maxParticipants || 0;
|
|
|
|
|
|
|
|
return api.createRoom(name, access, maxParticipants).then(room => {
|
2020-04-26 11:36:41 +02:00
|
|
|
setRooms(rooms.concat([room]));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateRoom(room: Room) {
|
2020-06-04 14:01:31 +02:00
|
|
|
return api.updateRoom(room).then(updatedRoom => {
|
2020-04-26 11:36:41 +02:00
|
|
|
setRooms(rooms.map(room => {
|
|
|
|
if (room.id === updatedRoom.id) {
|
|
|
|
return updatedRoom;
|
|
|
|
}
|
|
|
|
|
|
|
|
return room;
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function deleteRoom(id: number) {
|
|
|
|
api.deleteRoom(id).then(deletedRoom => {
|
|
|
|
setRooms(rooms.filter(room => room.id !== deletedRoom.id));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-08-27 17:21:34 +02:00
|
|
|
const maxRooms = restriction?.maxRooms || 0;
|
2020-08-29 15:10:52 +02:00
|
|
|
const quota = maxRooms < 0 ? t('bbb', 'unlimited') : rooms.filter(room => room.userId === OC.currentUser).length + ' / ' + maxRooms;
|
2020-08-27 17:21:34 +02:00
|
|
|
|
2020-04-26 11:36:41 +02:00
|
|
|
return (
|
2020-04-26 13:26:34 +02:00
|
|
|
<div id="bbb-react-root"
|
2020-04-26 11:36:41 +02:00
|
|
|
onClick={() => { /* @TODO hide edit inputs */ }}>
|
|
|
|
<table>
|
|
|
|
<thead>
|
|
|
|
<tr>
|
2020-05-17 16:51:26 +02:00
|
|
|
<th />
|
2020-04-26 11:36:41 +02:00
|
|
|
<th />
|
|
|
|
<th />
|
|
|
|
<th onClick={() => onOrderBy('name')}>
|
2020-05-16 14:44:21 +02:00
|
|
|
{t('bbb', 'Name')} <SortArrow name='name' value={orderBy} direction={sortOrder} />
|
2020-04-26 11:36:41 +02:00
|
|
|
</th>
|
2020-06-17 10:56:28 +02:00
|
|
|
<th />
|
2020-09-08 17:13:21 +02:00
|
|
|
<th onClick={() => onOrderBy('access')} className="bbb-shrink">
|
|
|
|
{t('bbb', 'Access')} <SortArrow name='access' value={orderBy} direction={sortOrder} />
|
|
|
|
</th>
|
2020-06-17 11:08:31 +02:00
|
|
|
<th onClick={() => onOrderBy('maxParticipants')} className="bbb-shrink">
|
2020-05-16 14:44:21 +02:00
|
|
|
{t('bbb', 'Max')} <SortArrow name='maxParticipants' value={orderBy} direction={sortOrder} />
|
2020-04-26 11:36:41 +02:00
|
|
|
</th>
|
2020-06-17 11:08:31 +02:00
|
|
|
<th onClick={() => onOrderBy('record')} className="bbb-shrink">
|
2020-05-16 14:44:21 +02:00
|
|
|
{t('bbb', 'Record')} <SortArrow name='record' value={orderBy} direction={sortOrder} />
|
2020-04-26 11:36:41 +02:00
|
|
|
</th>
|
2020-05-17 11:09:16 +02:00
|
|
|
<th>
|
|
|
|
{t('bbb', 'Recordings')}
|
|
|
|
</th>
|
2020-04-26 11:36:41 +02:00
|
|
|
<th />
|
2020-06-04 14:01:31 +02:00
|
|
|
<th />
|
2020-04-26 11:36:41 +02:00
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
|
|
|
{rows}
|
|
|
|
</tbody>
|
|
|
|
<tfoot>
|
|
|
|
<tr>
|
2020-05-17 16:51:26 +02:00
|
|
|
<td colSpan={3}>
|
2020-06-17 10:52:15 +02:00
|
|
|
{error && <><span className="icon icon-error icon-visible"></span> {error}</>}
|
2020-09-08 16:59:39 +02:00
|
|
|
{!isLoaded && <span className="icon icon-loading-small icon-visible"></span>}
|
2020-05-17 12:10:56 +02:00
|
|
|
</td>
|
2020-04-26 11:36:41 +02:00
|
|
|
<td>
|
2020-08-27 17:21:34 +02:00
|
|
|
{(maxRooms > rows.length || maxRooms < 0) ?
|
|
|
|
<NewRoomForm addRoom={addRoom} /> :
|
|
|
|
<p className="text-muted">{maxRooms === 0 ?
|
|
|
|
t('bbb', 'You are not permitted to create a room.') :
|
|
|
|
t('bbb', 'You exceeded the maximum number of rooms.')
|
|
|
|
}</p>}
|
2020-04-26 11:36:41 +02:00
|
|
|
</td>
|
2020-08-29 09:29:43 +02:00
|
|
|
<td />
|
|
|
|
<td colSpan={3}>
|
2020-08-29 15:10:52 +02:00
|
|
|
<p className="text-muted">{t('bbb', 'Room quota:')} {quota}</p>
|
2020-08-29 09:29:43 +02:00
|
|
|
</td>
|
2020-04-26 11:36:41 +02:00
|
|
|
</tr>
|
|
|
|
</tfoot>
|
|
|
|
</table>
|
|
|
|
</div>
|
2020-04-27 16:50:45 +02:00
|
|
|
);
|
|
|
|
};
|
2020-04-26 11:36:41 +02:00
|
|
|
|
2020-08-27 17:21:34 +02:00
|
|
|
export default App;
|