diff --git a/src/pages/index.js b/src/pages/index.js
index da93824..f0031b6 100644
--- a/src/pages/index.js
+++ b/src/pages/index.js
@@ -10,7 +10,7 @@ import Composer from '../components/composer'
import styles from './index.module.css'
import constants from '../constants.json'
-const forumPostPerPage = 2
+const forumPostPerPage = 5
const frontpageForumName = 'frontpage'
function fetchForum(from) {
diff --git a/src/pages/userFiles.js b/src/pages/userFiles.js
new file mode 100644
index 0000000..c49c249
--- /dev/null
+++ b/src/pages/userFiles.js
@@ -0,0 +1,330 @@
+import React, { useState, useEffect } from 'react'
+import Head from 'next/head'
+
+import LoadingIndicator from '../components/LoadingIndicator'
+import Modal from '../components/modal'
+
+import styles from './userFiles.module.css'
+import constants from '../constants.json'
+
+function listUserDir(subdir) {
+ return new Promise((resolve) => {
+ fetch(
+ `${constants.apiUrl}listUserDir${subdir ? `?subdir=${subdir}` : ''}`,
+ {
+ credentials: 'include',
+ }
+ )
+ .then((resp) => {
+ return resp.json()
+ })
+ .then((res) => {
+ if (res.success) {
+ resolve(res)
+ } else {
+ alert(res.msg)
+ }
+ })
+ })
+}
+
+function FileUploader({ onChange }) {
+ return (
+
+ )
+}
+
+function deleteFile(currDir, name) {
+ return new Promise((resolve) => {
+ fetch(constants.apiUrl + 'deleteUserFile', {
+ method: 'POST',
+ credentials: 'include',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ dir: currDir,
+ fname: name,
+ }),
+ })
+ .then((res) => {
+ return res.json()
+ })
+ .then((res) => {
+ if (res.success) {
+ resolve(res)
+ } else {
+ alert(res.msg)
+ }
+ })
+ })
+}
+
+function newSubj(name) {
+ return new Promise((resolve) => {
+ fetch(constants.apiUrl + 'newUserDir', {
+ method: 'POST',
+ credentials: 'include',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ name: name,
+ }),
+ })
+ .then((res) => {
+ return res.json()
+ })
+ .then((res) => {
+ if (res.success) {
+ resolve(res)
+ } else {
+ alert(res.msg)
+ }
+ })
+ })
+}
+
+function uploadFile(dir, file) {
+ return new Promise((resolve) => {
+ const formData = new FormData() // eslint-disable-line
+ formData.append('file', file)
+ formData.append('dir', dir)
+
+ fetch(constants.apiUrl + 'uploadUserFile', {
+ method: 'POST',
+ credentials: 'include',
+ headers: {
+ Accept: 'application/json',
+ },
+ body: formData,
+ })
+ .then((res) => {
+ return res.json()
+ })
+ .then((res) => {
+ resolve(res)
+ })
+ })
+}
+
+export default function UserFiles({ router, globalData }) {
+ const userId = globalData.userId
+ const [dirs, setDirs] = useState()
+ const [sortBy, setSortBy] = useState('name')
+ const [sortDirection, setSortDirection] = useState(true)
+ const [addingNew, setAddingNew] = useState()
+ const [newSubjName, setNewSubjName] = useState()
+ const [file, setFile] = useState()
+
+ const currDir = router.query.dir ? decodeURIComponent(router.query.dir) : ''
+
+ useEffect(() => {
+ const dir = router.query.dir ? decodeURIComponent(router.query.dir) : ''
+ setDirs(null)
+
+ if (router.query.dir) {
+ listUserDir(dir).then((res) => {
+ setDirs(res.files)
+ })
+ } else {
+ listUserDir().then((res) => {
+ setDirs(res.dirs)
+ })
+ }
+ }, [router.query.dir])
+
+ const dirSorter = (a, b) => {
+ if (a[sortBy] < b[sortBy]) {
+ return sortDirection ? -1 : 1
+ } else if (a[sortBy] > b[sortBy]) {
+ return sortDirection ? 1 : -1
+ } else {
+ return 0
+ }
+ }
+
+ const renderDirList = (dirs) => {
+ return (
+
+ {currDir && (
+
+
{
+ router.back()
+ // FIXME: consistend going back with browser back button
+ // back button works like broser back button, unless it would result in site leave
+ // history: nothing > opened site/usrFiles?dir=...
+ // history: site > site/userFiles > site/usrFiles?dir=...
+ router.push(`${router.pathname}`, undefined, { shallow: true })
+ }}
+ >
+ Vissza
+
+
+ )}
+
+
{
+ const name = e.target.getAttribute('name')
+ if (name) {
+ if (sortBy === name) {
+ setSortDirection(!sortDirection)
+ } else {
+ setSortDirection(true)
+ }
+ setSortBy(name)
+ }
+ }}
+ >
+
Fájl név
+
Feltöltés dátuma
+
Méret
+
Feltöltő user
+
+
+
+
{
+ setAddingNew(currDir ? 'file' : 'dir')
+ }}
+ >
+
{currDir ? 'Új fájl feltöltése...' : 'Új tárgy...'}
+
+ {dirs.length !== 0 && (
+ <>
+ {dirs.sort(dirSorter).map((dir) => {
+ const { name, date, path, size, user } = dir
+ return (
+
{
+ if (path) {
+ window.open(`${constants.apiUrl}${path}`, '_blank')
+ } else {
+ router.push(
+ `${router.pathname}?dir=${encodeURIComponent(name)}`,
+ undefined,
+ { shallow: true }
+ )
+ }
+ }}
+ >
+
{name}
+
{new Date(date).toDateString()}
+
+ {currDir
+ ? (size / 1000000).toFixed(2).toString() + ' MB'
+ : size + ' fájl'}
+
+
+ {user &&
+ user !== -1 &&
+ (userId === user ? (
+
{
+ e.stopPropagation()
+ if (confirm(`Biztos törlöd '${name}'-t ?`)) {
+ deleteFile(currDir, name).then(() => {
+ listUserDir(currDir).then((res) => {
+ setDirs(res.files)
+ })
+ })
+ }
+ }}
+ >
+ Törlés
+
+ ) : (
+ `#${user}`
+ ))}
+
+
+ )
+ })}
+ >
+ )}
+
+
+ )
+ }
+
+ return (
+
+
+
Study Docs - Qmining | Frylabs.net
+
+
+
Study Docs
+
+
+ Ide tárgyanként lehet feltölteni
+
+ {dirs ? renderDirList(dirs) :
}
+ {addingNew && (
+
{
+ setAddingNew(null)
+ }}
+ >
+
+ {addingNew === 'file' ? (
+ <>
+
{
+ setFile(e.target.files[0])
+ }}
+ />
+ {
+ uploadFile(currDir, file).then(() => {
+ listUserDir(currDir).then((res) => {
+ setDirs(res.files)
+ setAddingNew(null)
+ })
+ })
+ }}
+ >
+
Feltöltés
+
+ >
+ ) : (
+ <>
+ Új tárgy neve
+
+ {
+ setNewSubjName(e.target.value)
+ }}
+ />
+
+ {
+ newSubj(newSubjName).then(() => {
+ listUserDir().then((res) => {
+ setDirs(res.dirs)
+ setAddingNew(null)
+ })
+ })
+ }}
+ >
+
OK
+
+ >
+ )}
+
+
+ )}
+
+ )
+}
diff --git a/src/pages/userFiles.module.css b/src/pages/userFiles.module.css
new file mode 100644
index 0000000..1abb5a0
--- /dev/null
+++ b/src/pages/userFiles.module.css
@@ -0,0 +1,78 @@
+.tableContainer {
+ user-select: none;
+ display: flex;
+ flex-flow: column;
+}
+
+.tableContainer > div {
+ padding: 15px 5px;
+ display: flex;
+ align-items: stretch;
+}
+
+.tableContainer > div > div {
+ padding: 5px;
+}
+
+.tableContainer > div > div:nth-child(1) {
+ flex: 1;
+}
+
+.tableContainer > div > div:nth-child(2) {
+ flex: 0 240px;
+}
+.tableContainer > div > div:nth-child(3) {
+ flex: 0 160px;
+}
+
+.tableContainer > div > div:nth-child(4) {
+ flex: 0 100px;
+}
+
+.rows > div {
+ cursor: pointer;
+}
+
+.rows > div:nth-child(2n + 1) {
+ background-color: var(--dark-color);
+}
+
+.rows > div:hover {
+ background-color: var(--hoover-color);
+}
+
+.header > div > div {
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+}
+
+.header > div > div:hover {
+ background-color: var(--hoover-color);
+}
+
+.uploadContainer > div {
+ padding: 5px;
+ text-align: center;
+}
+
+.deleteButton {
+ text-align: center;
+ padding: 2px;
+ border: 1px solid var(--hoover-color);
+ border-radius: 3px;
+ cursor: pointer;
+}
+
+.deleteButton:hover {
+ background-color: var(--dark-color);
+}
+
+.backButton {
+ width: 30%;
+}
+
+.description {
+ padding: 5px;
+ text-align: center;
+}