Minor chages including class name rename, max entries to load on front page

This commit is contained in:
mrfry 2021-04-20 10:19:02 +02:00
parent b88a4d9c9e
commit a91fa4a7fe
8 changed files with 417 additions and 15 deletions

View file

@ -1,3 +1,4 @@
import React from 'react'
import styles from './button.module.css' import styles from './button.module.css'
export default function Button(props) { export default function Button(props) {
@ -5,7 +6,7 @@ export default function Button(props) {
<div> <div>
<center> <center>
<a href={props.href}> <a href={props.href}>
<div className={styles.ircLink}>{props.text}</div> <div className={styles.button}>{props.text}</div>
</a> </a>
</center> </center>
</div> </div>

View file

@ -1,4 +1,4 @@
.ircLink { .button {
background-color: #9999ff; background-color: #9999ff;
border: none; border: none;
color: white; color: white;

View file

@ -78,6 +78,7 @@ export default function AllQuestions({ router }) {
const [selectedDb, setSelectedDb] = useState('') const [selectedDb, setSelectedDb] = useState('')
const [data, setData] = useState(null) const [data, setData] = useState(null)
const [fetchingData, setFetchingData] = useState(false) const [fetchingData, setFetchingData] = useState(false)
const subjectCount = data ? data.length : 0 const subjectCount = data ? data.length : 0
const questionCount = data ? data.reduce(countReducer, 0) : 0 const questionCount = data ? data.reduce(countReducer, 0) : 0
@ -296,6 +297,8 @@ export default function AllQuestions({ router }) {
</div> </div>
)} )}
</> </>
) : fetchingData ? (
<LoadingIndicator />
) : null} ) : null}
</div> </div>
) )

View file

@ -43,7 +43,8 @@ export default function Contact() {
<div> <div>
<div className={'subtitle'}>Üzenet küldése</div> <div className={'subtitle'}>Üzenet küldése</div>
<div className={styles.text}> <div className={styles.text}>
Weboldalon keresztüli üzenetküldés az adminnak (feedback) Weboldalon keresztüli üzenetküldés az adminnak (feedback). Válasz bal
alsó levelesládába (📬) érkezik majd.
</div> </div>
</div> </div>
<FeedbackArea from={'contact'} /> <FeedbackArea from={'contact'} />

View file

@ -42,17 +42,6 @@ export default function contribute() {
<br /> A kurzort az oszlopcímekre mozgatva, további információkat <br /> A kurzort az oszlopcímekre mozgatva, további információkat
olvashatsz a kategóriák tulajdonságairól. olvashatsz a kategóriák tulajdonságairól.
</p> </p>
{
'Ha olyan teendőt látsz, amiben tudnál és szeretnél is segíteni, akkor írj '
}
<a
href="http://qmining.frylabs.net/irc?contribute"
target="_blank"
rel="noreferrer"
>
{'IRC'}
</a>
-n és megbeszéljük.
</div> </div>
<center> <center>
<div className={`buttonContainer ${styles.newTaskButton}`}> <div className={`buttonContainer ${styles.newTaskButton}`}>

View file

@ -10,7 +10,7 @@ import Composer from '../components/composer'
import styles from './index.module.css' import styles from './index.module.css'
import constants from '../constants.json' import constants from '../constants.json'
const forumPostPerPage = 2 const forumPostPerPage = 5
const frontpageForumName = 'frontpage' const frontpageForumName = 'frontpage'
function fetchForum(from) { function fetchForum(from) {

330
src/pages/userFiles.js Normal file
View file

@ -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 (
<div>
<div>Fájl csatolása</div>
<input type="file" name="file" onChange={onChange} />
</div>
)
}
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 (
<div>
{currDir && (
<div className={`buttonContainer ${styles.backButton}`}>
<div
onClick={() => {
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
</div>
</div>
)}
<div className={`${styles.tableContainer} ${styles.header}`}>
<div
onClick={(e) => {
const name = e.target.getAttribute('name')
if (name) {
if (sortBy === name) {
setSortDirection(!sortDirection)
} else {
setSortDirection(true)
}
setSortBy(name)
}
}}
>
<div name="name">Fájl név</div>
<div name="date">Feltöltés dátuma</div>
<div name="size">Méret</div>
<div name="user">Feltöltő user</div>
</div>
</div>
<div className={`${styles.tableContainer} ${styles.rows}`}>
<div
onClick={() => {
setAddingNew(currDir ? 'file' : 'dir')
}}
>
<div>{currDir ? 'Új fájl feltöltése...' : 'Új tárgy...'}</div>
</div>
{dirs.length !== 0 && (
<>
{dirs.sort(dirSorter).map((dir) => {
const { name, date, path, size, user } = dir
return (
<div
title={name}
key={name}
onClick={() => {
if (path) {
window.open(`${constants.apiUrl}${path}`, '_blank')
} else {
router.push(
`${router.pathname}?dir=${encodeURIComponent(name)}`,
undefined,
{ shallow: true }
)
}
}}
>
<div>{name}</div>
<div>{new Date(date).toDateString()}</div>
<div>
{currDir
? (size / 1000000).toFixed(2).toString() + ' MB'
: size + ' fájl'}
</div>
<div>
{user &&
user !== -1 &&
(userId === user ? (
<div
className={styles.deleteButton}
onClick={(e) => {
e.stopPropagation()
if (confirm(`Biztos törlöd '${name}'-t ?`)) {
deleteFile(currDir, name).then(() => {
listUserDir(currDir).then((res) => {
setDirs(res.files)
})
})
}
}}
>
Törlés
</div>
) : (
`#${user}`
))}
</div>
</div>
)
})}
</>
)}
</div>
</div>
)
}
return (
<div>
<Head>
<title>Study Docs - Qmining | Frylabs.net</title>
</Head>
<div className="pageHeader">
<h1>Study Docs</h1>
</div>
<div className={styles.description}>
Ide tárgyanként lehet feltölteni
</div>
{dirs ? renderDirList(dirs) : <LoadingIndicator />}
{addingNew && (
<Modal
closeClick={() => {
setAddingNew(null)
}}
>
<div className={styles.uploadContainer}>
{addingNew === 'file' ? (
<>
<FileUploader
onChange={(e) => {
setFile(e.target.files[0])
}}
/>
<div
className="buttonContainer"
onClick={() => {
uploadFile(currDir, file).then(() => {
listUserDir(currDir).then((res) => {
setDirs(res.files)
setAddingNew(null)
})
})
}}
>
<div>Feltöltés</div>
</div>
</>
) : (
<>
<div>Új tárgy neve</div>
<div>
<input
type="text"
onChange={(e) => {
setNewSubjName(e.target.value)
}}
/>
</div>
<div
className="buttonContainer"
onClick={() => {
newSubj(newSubjName).then(() => {
listUserDir().then((res) => {
setDirs(res.dirs)
setAddingNew(null)
})
})
}}
>
<div>OK</div>
</div>
</>
)}
</div>
</Modal>
)}
</div>
)
}

View file

@ -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;
}