diff --git a/docs/thi-rest-api.md b/docs/thi-rest-api.md index 262c2fd9..8f39c9db 100644 --- a/docs/thi-rest-api.md +++ b/docs/thi-rest-api.md @@ -598,189 +598,3 @@ to: c "status": 0 } ``` - -## Reservations (library) - -### getreservation - -```http -service: thiapp -method: reservations -format: json -session: -type: 1 -subtype: 1 -cmd: getreservation -data: -``` - -As of 2021-06 the API returns "Service not available" when no reservations are available - -```json -{ - "data": "Service not available", - "date": "10.06.2021", - "time": "14:23:27", - "status": -112 -} -``` - -Old response: - -```json -{ - "data": "No reservation data", - "date": "02.11.2020", - "status": -126, - "time": "20:36:31" -} -``` - -```json -{ - "data": [ - 0, - [ - { - "rcategory": "Lesesaal Galerie", - "reservation_begin": "2020-11-03 06:00:00", - "reservation_end": "2020-11-03 10:00:00", - "reservation_id": "6678", - "reserved_at": "2020-11-02 20:25:50", - "reserved_by": "", - "resource": "2", - "resource_id": "3", - "rsubtype": "1" - } - ] - ], - "date": "02.11.2020", - "status": 0, - "time": "20:34:29" -} -``` - -### addreservation - -```http -service: thiapp -method: reservations -format: json -session: -type: 1 -subtype: 1 -cmd: addreservation -data: {"resource":"3","from":"06:00","to":"10:00","at":"2020-11-03","place":"-1"} -``` - -```json -{ - "data": [0, [""]], - "date": "02.11.2020", - "status": 0, - "time": "21:29:51" -} -``` - -### delreservation - -```http -service: thiapp -method: reservations -format: json -session: -type: 1 -subtype: 1 -cmd: delreservation -data: 6678 -``` - -```json -{ - "data": "No reservation data", - "date": "02.11.2020", - "status": -126, - "time": "20:36:31" -} -``` - -### getavailabilities - -```http -service: thiapp -method: reservations -format: json -session: -type: 1 -subtype: 1 -cmd: getavailabilities -data: -``` - -parts redacted, see getavailabilities-full.json - -```json -{ - "date": "02.11.2020", - "time": "20:37:54", - "data": [ - 0, - [ - { - "date": "2020-11-02", - "hasReservation": false, - "resource": [ - { - "from": "18:00", - "to": "24:00", - "resources": { - "1": { - "room_name": "Lesesaal Nord (alte Bibliothek)", - "seats": [ - "1", - "4", - "5", - "8", - "9", - "12", - "14", - "16", - "18", - "20", - "21", - "24", - "25", - "28", - "29", - "32", - "33", - "36", - "37", - "40", - "41", - "44", - "45", - "48", - "49", - "50", - "51", - "52", - "53", - "54", - "56", - "57" - ], - "num_seats": 32, - "maxnum_seats": 32 - } - // more rooms ... - } - } - ] - } - // more days, more times ... - ] - ], - "status": 0 -} -``` diff --git a/rogue-thi-app/components/allCards.jsx b/rogue-thi-app/components/allCards.jsx index e74da00e..b4c129de 100644 --- a/rogue-thi-app/components/allCards.jsx +++ b/rogue-thi-app/components/allCards.jsx @@ -7,7 +7,7 @@ import InstallPrompt from './cards/InstallPrompt' import RoomCard from './cards/RoomCard' import TimetableCard from './cards/TimetableCard' -import { GraduationCap, Library, Map, Scroll, User } from 'lucide-react' +import { GraduationCap, Map, Scroll, User } from 'lucide-react' import { USER_EMPLOYEE, USER_GUEST, USER_STUDENT } from '../lib/hooks/user-kind' // import ElectionPrompt from './cards/ElectionPrompt' @@ -102,19 +102,6 @@ export const ALL_DASHBOARD_CARDS = [ /> ), }, - { - key: 'library', - removable: true, - default: [PLATFORM_DESKTOP, PLATFORM_MOBILE, USER_STUDENT, USER_EMPLOYEE], - card: () => ( - - ), - }, { key: 'grades', removable: true, diff --git a/rogue-thi-app/lib/backend-utils/library-utils.js b/rogue-thi-app/lib/backend-utils/library-utils.js deleted file mode 100644 index cd940eea..00000000 --- a/rogue-thi-app/lib/backend-utils/library-utils.js +++ /dev/null @@ -1,26 +0,0 @@ -import API from '../backend/authenticated-api' -import { combineDateTime } from '../date-utils' - -/** - * Converts the seat list for easier processing. - * @returns {object} - */ -export async function getFriendlyAvailableLibrarySeats() { - const available = await API.getAvailableLibrarySeats() - return available.map((day) => { - const date = day.date.substring(0, 10) - return { - date, - resource: day.resource.map((slot) => { - const from = combineDateTime(date, slot.from) - const to = combineDateTime(date, slot.to) - - return { - ...slot, - from, - to, - } - }), - } - }) -} diff --git a/rogue-thi-app/lib/backend/authenticated-api.js b/rogue-thi-app/lib/backend/authenticated-api.js index e0aa5040..4b64e354 100644 --- a/rogue-thi-app/lib/backend/authenticated-api.js +++ b/rogue-thi-app/lib/backend/authenticated-api.js @@ -271,108 +271,6 @@ export class AuthenticatedAPIClient extends AnonymousAPIClient { return res } - async getLibraryReservations() { - try { - const res = await this.requestAuthenticated({ - service: 'thiapp', - method: 'reservations', - type: 1, - cmd: 'getreservations', - format: 'json', - }) - - return res[1] - } catch (e) { - // as of 2021-06 the API returns "Service not available" when the user has no reservations - // thus we dont alert the error here, but just silently set the reservations to none - if ( - e.data === 'No reservation data' || - e.data === 'Service not available' - ) { - return [] - } else { - throw e - } - } - } - - async getAvailableLibrarySeats() { - try { - const res = await this.requestAuthenticated({ - service: 'thiapp', - method: 'reservations', - type: 1, - subtype: 1, - cmd: 'getavailabilities', - format: 'json', - }) - - return res[1] - } catch (e) { - // Unbekannter Fehler means the user has already reserved a spot - // and can not reserve additional ones - if (e.data === 'Unbekannter Fehler') { - return [] - } else { - throw e - } - } - } - - /** - * TODO documentation - */ - async addLibraryReservation(roomId, day, start, end, place) { - const res = await this.requestAuthenticated({ - service: 'thiapp', - method: 'reservations', - type: 1, - subtype: 1, - cmd: 'addreservation', - data: JSON.stringify({ - resource: roomId, - at: day, - from: start, - to: end, - place, - }), - dblslots: 0, - format: 'json', - }) - - return res[0] - } - - /** - * @param {string} reservationId Reservation ID returned by `getLibraryReservations` - */ - async removeLibraryReservation(reservationId) { - try { - await this.requestAuthenticated({ - service: 'thiapp', - method: 'reservations', - type: 1, - subtype: 1, - cmd: 'delreservation', - data: reservationId, - format: 'json', - }) - - return true - } catch (e) { - // as of 2021-06 the API returns "Service not available" when the user has no reservations - // thus we dont alert the error here, but just silently set the reservations to none - if ( - e.data === 'No reservation data' || - e.data === 'Service not available' - ) { - return true - } else { - throw e - } - } - } - async getImprint() { const res = await this.requestAuthenticated({ service: 'thiapp', diff --git a/rogue-thi-app/pages/library.jsx b/rogue-thi-app/pages/library.jsx deleted file mode 100644 index 34073aaf..00000000 --- a/rogue-thi-app/pages/library.jsx +++ /dev/null @@ -1,324 +0,0 @@ -import React, { useEffect, useState } from 'react' -import { useRouter } from 'next/router' - -import Button from 'react-bootstrap/Button' -import Form from 'react-bootstrap/Form' -import ListGroup from 'react-bootstrap/ListGroup' -import Modal from 'react-bootstrap/Modal' -import ReactPlaceholder from 'react-placeholder' - -import { Trash } from 'lucide-react' - -import AppBody from '../components/page/AppBody' -import AppContainer from '../components/page/AppContainer' -import AppNavbar from '../components/page/AppNavbar' -import AppTabbar from '../components/page/AppTabbar' - -import { - NoSessionError, - UnavailableSessionError, -} from '../lib/backend/thi-session-handler' -import { - formatFriendlyDate, - formatFriendlyTime, - formatNearDate, -} from '../lib/date-utils' -import API from '../lib/backend/authenticated-api' -import { getFriendlyAvailableLibrarySeats } from '../lib/backend-utils/library-utils' - -import styles from '../styles/Library.module.css' - -import { Trans, useTranslation } from 'next-i18next' - -import { serverSideTranslations } from 'next-i18next/serverSideTranslations' - -/** - * Page for reserving library seats. - */ -export default function Library() { - const [reservations, setReservations] = useState(null) - const [available, setAvailable] = useState(null) - const [reservationDay, setReservationDay] = useState(false) - const [reservationTime, setReservationTime] = useState(false) - const [reservationRoom, setReservationRoom] = useState(1) - const [reservationSeat, setReservationSeat] = useState(-1) - const router = useRouter() - const { t } = useTranslation('library') - - /** - * Fetches and displays the reservation data. - */ - async function refreshData() { - const available = await getFriendlyAvailableLibrarySeats() - setAvailable(available) - - const response = await API.getLibraryReservations() - response.forEach((x) => { - x.start = new Date(x.reservation_begin.replace(' ', 'T')) - x.end = new Date(x.reservation_end.replace(' ', 'T')) - }) - setReservations(response) - } - - /** - * Closes the reservation popup. - */ - function hideReservationModal() { - setReservationDay(null) - setReservationTime(null) - } - - /** - * Cancels a reservation. - * @param {string} id Reservation ID - */ - async function deleteReservation(id) { - await API.removeLibraryReservation(id) - await refreshData() - } - - /** - * Creates a new reservation. - */ - async function addReservation() { - await API.addLibraryReservation( - reservationRoom, - reservationDay.date, - // this needs to be de-DE regardless of the users locale - reservationTime.from.toLocaleTimeString('de-DE', { timeStyle: 'short' }), - reservationTime.to.toLocaleTimeString('de-DE', { timeStyle: 'short' }), - reservationSeat - ) - await refreshData() - hideReservationModal() - } - - useEffect(() => { - async function load() { - try { - await refreshData() - } catch (e) { - if ( - e instanceof NoSessionError || - e instanceof UnavailableSessionError - ) { - router.replace('/login?redirect=library') - } else { - console.error(e) - alert(e) - } - } - } - load() - }, [router]) - - /** - * Returns a list of available rooms where are more than 0 seats available. - * @returns {Array} List of available rooms - **/ - function getAvailableRooms() { - return Object.entries(reservationTime.resources) - .map(([roomId, room], idx) => [roomId, room, idx]) - .filter(([, room]) => room.num_seats > 0) - } - - /** - * Returns the first available room. - * @returns {string} Room ID - * */ - function getFirstAvailableRoom() { - return getAvailableRooms()[0][0][0] - } - - return ( - - - - - setReservationRoom(getFirstAvailableRoom())} - > - - {t('library.modal.title')} - - - {t('library.modal.details.day')}:{' '} - {reservationDay && formatFriendlyDate(reservationDay.date)} -
- {t('library.modal.details.start')}:{' '} - {reservationTime && formatFriendlyTime(reservationTime.from)} -
- {t('library.modal.details.end')}:{' '} - {reservationTime && formatFriendlyTime(reservationTime.to)} -
-
- - {t('library.modal.details.location')}: - setReservationRoom(event.target.value)} - > - {reservationTime && - getAvailableRooms().map(([roomId, room, idx]) => ( - - ))} - - - - {t('library.modal.details.seat')}: - setReservationSeat(event.target.value)} - > - - {reservationTime && - reservationRoom && - Object.values( - reservationTime.resources[reservationRoom].seats - ).map((x, idx) => ( - - ))} - - -
- - - - -
- -

{t('library.yourReservations')}

- - - {reservations && reservations.length === 0 && ( - - {t('library.details.noReservations')} - - )} - {reservations && - reservations.map((x, i) => ( - -
- -
- , - }} - /> -
- {formatNearDate(x.start)}: {formatFriendlyTime(x.start)} -{' '} - {formatFriendlyTime(x.end)} -
- ))} -
-
- -

{t('library.availableSeats')}

- - - {available && - available.map((day, i) => - day.resource.map((time, j) => ( - - {Object.values(time.resources).reduce( - (acc, room) => acc + room.num_seats, - 0 - ) > 0 && ( - - )} - - {formatNearDate(time.from)} - {', '} - {formatFriendlyTime(time.from)} - {' - '} - {formatFriendlyTime(time.to)} -
-
- {t('library.details.seatsAvailable', { - available: Object.values(time.resources).reduce( - (acc, room) => acc + room.num_seats, - 0 - ), - total: Object.values(time.resources).reduce( - (acc, room) => acc + room.maxnum_seats, - 0 - ), - })} -
-
- )) - )} - {available && available.length === 0 && ( - - {t('library.details.noMoreReservations')} - - )} -
-
- - -
-
- ) -} - -export const getStaticProps = async ({ locale }) => ({ - props: { - ...(await serverSideTranslations(locale ?? 'en', ['library', 'common'])), - }, -}) diff --git a/rogue-thi-app/public/locales/de/common.json b/rogue-thi-app/public/locales/de/common.json index 404fe921..a15fb976 100644 --- a/rogue-thi-app/public/locales/de/common.json +++ b/rogue-thi-app/public/locales/de/common.json @@ -63,7 +63,6 @@ "events": "Campus Life", "rooms": "Raumvorschläge", "roomplan": "Raumkarte", - "library": "Bibliothek", "grades": "Noten & Fächer", "personal": "Profil", "lecturers": "Dozenten", diff --git a/rogue-thi-app/public/locales/de/dashboard.json b/rogue-thi-app/public/locales/de/dashboard.json index 26a3e3d7..a104b023 100644 --- a/rogue-thi-app/public/locales/de/dashboard.json +++ b/rogue-thi-app/public/locales/de/dashboard.json @@ -60,9 +60,6 @@ "roomplan": { "title": "Raumkarte" }, - "library": { - "title": "Bibliothek" - }, "grades": { "title": "Noten & Fächer" }, diff --git a/rogue-thi-app/public/locales/de/library.json b/rogue-thi-app/public/locales/de/library.json deleted file mode 100644 index 7b98b849..00000000 --- a/rogue-thi-app/public/locales/de/library.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "library": { - "title": "Bibliothek", - "yourReservations": "Deine Reservierungen", - "availableSeats": "Verfügbare Plätze", - "actions": { - "reserve": "Reservieren", - "delete": "Löschen" - }, - "details": { - "seatsAvailable": "{{available}} / {{total}} verfügbar", - "noReservations": "Du hast keine Reservierungen", - "noMoreReservations": "Du kannst keine weiteren Plätze reservieren", - "reservationDetails": "{{category}}, Platz {{seat}}, Reservierung {{reservation_id}}" - }, - "modal": { - "title": "Sitzplatz reservieren", - "details": { - "day": "Tag", - "start": "Start", - "end": "Ende", - "location": "Ort", - "seat": "Sitz" - }, - "seatSelection": { - "any": "Egal" - }, - "librarySelection": { - "libraryNorth": "Lesesaal Nord (alte Bibliothek)", - "librarySouth": "Lesesaal Süd (neue Bibliothek)", - "libraryGallery": "Lesesaal Galerie" - }, - "actions": { - "cancel": "Abbrechen", - "reserve": "Reservieren" - } - } - } -} diff --git a/rogue-thi-app/public/locales/en/common.json b/rogue-thi-app/public/locales/en/common.json index 95407bb2..2f24db75 100644 --- a/rogue-thi-app/public/locales/en/common.json +++ b/rogue-thi-app/public/locales/en/common.json @@ -63,7 +63,6 @@ "events": "Campus Life", "rooms": "Room Suggestions", "roomplan": "Room Map", - "library": "Library", "grades": "Grades & Subjects", "personal": "Profile", "lecturers": "Lecturers", diff --git a/rogue-thi-app/public/locales/en/dashboard.json b/rogue-thi-app/public/locales/en/dashboard.json index 4a551d18..0e30ba28 100644 --- a/rogue-thi-app/public/locales/en/dashboard.json +++ b/rogue-thi-app/public/locales/en/dashboard.json @@ -60,9 +60,6 @@ "roomplan": { "title": "Room Map" }, - "library": { - "title": "Library" - }, "grades": { "title": "Grades & Subjects" }, diff --git a/rogue-thi-app/public/locales/en/library.json b/rogue-thi-app/public/locales/en/library.json deleted file mode 100644 index 267110ad..00000000 --- a/rogue-thi-app/public/locales/en/library.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "library": { - "title": "Library", - "yourReservations": "Your reservations", - "availableSeats": "Available seats", - "actions": { - "reserve": "Reserve", - "delete": "Delete" - }, - "details": { - "seatsAvailable": "{{available}} / {{total}} available", - "noReservations": "You have no reservations", - "noMoreReservations": "You can not reserve any more seats", - "reservationDetails": "{{category}}, Seat {{seat}}, Reservation {{reservation_id}}" - }, - "modal": { - "title": "Reserve a seat", - "details": { - "day": "Day", - "start": "Start", - "end": "End", - "location": "Location", - "seat": "Seat" - }, - "seatSelection": { - "any": "Any" - }, - "librarySelection": { - "libraryNorth": "Lesesaal Nord (alte Bibliothek)", - "librarySouth": "Lesesaal Süd (neue Bibliothek)", - "libraryGallery": "Lesesaal Galerie" - }, - "actions": { - "cancel": "Cancel", - "reserve": "Reserve" - } - } - } -} diff --git a/rogue-thi-app/styles/Library.module.css b/rogue-thi-app/styles/Library.module.css deleted file mode 100644 index f7a8abe1..00000000 --- a/rogue-thi-app/styles/Library.module.css +++ /dev/null @@ -1,17 +0,0 @@ -.heading { - margin-top: 20px; -} - -.floatRight { - right: 20px; - top: 50%; - transform: translateY(-50%); - position: absolute; -} - -.cancelButton { - display: flex; - justify-content: center; - align-items: center; - padding: 10px; -}