1
0
Fork 0
mirror of https://gitlab.com/MrFry/qmining-page synced 2025-04-01 20:23:44 +02:00
qmining-page/src/pages/userfiles.js
2022-11-21 14:50:52 +01:00

606 lines
17 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect, useCallback } from 'react'
import Link from 'next/link'
import LoadingIndicator from '../components/LoadingIndicator'
import Modal from '../components/modal'
import SearchBar from '../components/searchBar'
import UpDownVote from '../components/upDownVote'
import Header from '../components/header'
import styles from './userfiles.module.css'
import constants from '../constants.json'
function vote(to, item) {
return new Promise((resolve, reject) => {
fetch(`${constants.apiUrl}voteFile`, {
method: 'POST',
credentials: 'include',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
path: item.path,
to: to,
}),
})
.then((resp) => {
return resp.json()
})
.then((res) => {
if (res.success) {
resolve(res)
} else {
reject(res)
}
})
})
}
function listUserDir(subdir) {
return new Promise((resolve, reject) => {
fetch(
`${constants.apiUrl}listUserDir${subdir ? `?subdir=${subdir}` : ''}`,
{
credentials: 'include',
}
)
.then((resp) => {
return resp.json()
})
.then((res) => {
if (res.success) {
resolve(res)
} else {
reject(res)
}
})
})
}
function FileUploader({ onChange, uploading }) {
return (
<div>
<div className={styles.text}>
<b>
Fontos a névtelenség, ezért figyelj milyen személyes adatokat
tartalmaz a feltöltött dokumentum!
</b>
<p />
Amit feltöltesz minden felhasználó lát. Csak ide illő tartalmat ossz
meg.
<p />
</div>
{uploading ? (
<LoadingIndicator />
) : (
<input type="file" name="file" onChange={onChange} />
)}
</div>
)
}
function SubjNameInput({ onChange, uploading }) {
return (
<>
<div className={styles.text}>
Tárgyat kérlek úgy nevezd el, hogy: [tárgy neve] - [egyetem rövid
azonosító], szóval pl: Elektronika - OE.
<p />
Üres mappák időnként törölve lesznek.
</div>
<p />
{uploading ? (
<LoadingIndicator />
) : (
<div>
<input
autoFocus
placeholder={'Új tárgy neve'}
type="text"
onChange={(e) => {
onChange(e.target.value)
}}
/>
</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,
globalState,
setGlobalState,
}) {
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 [searchTerm, setSearchTerm] = useState()
const [uploading, setUploading] = useState(false)
const [votingDisabled, setVotingDisabled] = useState(false)
const currDir = router.query.dir ? decodeURIComponent(router.query.dir) : ''
const goBack = useCallback(() => {
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,
})
}, [router])
const deleteDirectory = useCallback(
(dirName) => {
fetch(constants.apiUrl + 'deleteDir', {
method: 'POST',
credentials: 'include',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: dirName,
}),
})
.then((res) => {
return res.json()
})
.then((res) => {
console.info(res)
if (res.succes) {
getRootDir(true)
alert(`a(z) '${dirName}' mappa törölve!`)
} else {
alert('Hiba törlés közben!')
}
})
.catch((e) => {
alert('Hálózati hiba!')
})
},
[router]
)
useEffect(() => {
router.replace(`${router.asPath.replace('.html', '')}`, undefined, {
shallow: true,
})
}, [])
useEffect(() => {
const dir = router.query.dir ? decodeURIComponent(router.query.dir) : ''
setDirs(null)
setSearchTerm()
if (router.query.dir) {
getDir(dir)
} else {
getRootDir()
}
}, [router.query.dir])
const getDir = (dir, nocache) => {
if (!nocache && globalState.userFiles && globalState.userFiles[dir]) {
setDirs(globalState.userFiles[dir])
} else {
listUserDir(dir)
.then((res) => {
setDirs(res.files)
setGlobalState({
userFiles: {
...globalState.userFiles,
[dir]: res.files,
},
})
})
.catch((res) => {
alert(res.msg)
})
}
}
const getRootDir = (nocache) => {
if (!nocache && globalState.userFilesRoot) {
setDirs(globalState.userFilesRoot)
} else {
listUserDir()
.then((res) => {
setGlobalState({
userFilesRoot: res.dirs,
})
setDirs(res.dirs)
})
.catch((res) => {
alert(res.msg)
})
}
}
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 handleVote = (type, dir) => {
setVotingDisabled(true)
vote(type, dir)
.then((res) => {
setDirs(res.files)
setVotingDisabled(false)
})
.catch((res) => {
alert(res.msg)
setVotingDisabled(false)
})
}
const renderNewButton = () => (
<div className={`buttonContainer ${styles.newButton}`}>
<div
onClick={() => {
setAddingNew(currDir ? 'file' : 'dir')
}}
>
{currDir ? 'Új fájl feltöltése...' : ' Új tárgy hozzáadása...'}
</div>
</div>
)
const renderDirList = (dirs) => {
return (
<div>
{currDir && (
<div className={styles.title}>
{currDir && <div className={styles.currDir}>{currDir}</div>}
</div>
)}
<div style={{ display: 'flex' }}>
<div style={{ flexGrow: 1 }}>
<SearchBar
searchTerm={searchTerm}
onChange={(e) => {
setSearchTerm(e)
}}
/>
</div>
{renderNewButton()}
</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="upCount">Hasznos</div>
<div name="views">Letöltések</div>
<div name="user">Feltöltő user</div>
</div>
</div>
{dirs ? (
<div className={`${styles.tableContainer} ${styles.rows}`}>
{currDir && (
<div
style={{ height: 40, justifyContent: "center", display: "flex" }}
onClick={() => {
goBack()
}}
>
{'Vissza'}
</div>
)}
{dirs.length !== 0 ? (
<>
{dirs.sort(dirSorter).map((dir) => {
const {
name,
date,
path,
size,
views,
user,
upvotes,
downvotes,
} = dir
if (
searchTerm &&
!name.toLowerCase().includes(searchTerm.toLowerCase())
) {
return null
}
return (
<div
title={name}
key={name}
onClick={() => {
if (path) {
window.open(`${constants.apiUrl}${path}`, '_blank')
} else {
setDirs(undefined)
router.push(
`${router.pathname}?dir=${encodeURIComponent(
name
)}`,
undefined,
{ shallow: true }
)
}
}}
>
<div>{name}</div>
<div title={new Date(date).toLocaleString()}>
{new Date(date).toLocaleDateString()}
</div>
<div>
{currDir
? (size / 1000000).toFixed(2).toString() + ' MB'
: size + ' fájl'}
</div>
<div>
{Array.isArray(upvotes) && Array.isArray(downvotes) && (
<UpDownVote
onUp={() => {
handleVote('up', dir)
}}
onDown={() => {
handleVote('down', dir)
}}
onClear={() => {
handleVote('clear', dir)
}}
upvotes={upvotes}
downvotes={downvotes}
userId={userId}
disabled={votingDisabled}
/>
)}
</div>
<div>{!isNaN(views) && `${views} db`}</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(() => {
getDir(currDir, true)
})
}
}}
>
Törlés
</div>
) : (
<Link href={`/chat?user=${user}`}>
<a
title={`Chat #${user}-el`}
onClick={(e) => {
e.stopPropagation()
}}
className={'userId'}
>{`#${user}`}</a>
</Link>
))}
</div>
</div>
)
})}
</>
) : (
<div
title={'A megnyitott mappa törlése, mivel üres'}
onClick={() => {
if (
window.confirm(
`Biztosan törlöd a(z) '${currDir}' üres mappát?`
)
) {
deleteDirectory(currDir)
goBack()
}
}}
>
{'Mappa törlése'}
</div>
)}
</div>
) : (
<LoadingIndicator />
)}
</div>
)
}
return (
<div>
<Header title={'ZH-k/Vizsgák, segédanyagok'} />
<div className="pageHeader">
<h1>ZH-k/Vizsgák, segédanyagok</h1>
</div>
{!currDir && (
<div className={styles.description}>
Itt lehet megosztani mindenféle tanulást segítő doksit (kidolgozott
tételektől puskáig mindent).
<br />
Ez gyakorlatilag egy fájl böngésző, a tárgyak a mappák, és azon belül
lehet fájlokat feltölteni.
<br />A feltöltött fájlok ellenőrizve vannak, hogy ide valóak-e, de{' '}
<b>
hibás információért, vírusokért és hasonlókért semmi felelősség
vállalás nincs.
</b>{' '}
Ha valami nem idevalót látsz, azt a{' '}
<Link href="/contact">
<a>Kapcsolat</a>
</Link>{' '}
oldalon jelezd kérlek. Tudatos károkozásért ban jár.
</div>
)}
<hr />
{renderDirList(dirs)}
{addingNew && (
<Modal
closeClick={() => {
setAddingNew(null)
}}
>
<div className={styles.uploadContainer}>
{addingNew === 'file' ? (
<>
<FileUploader
uploading={uploading}
onChange={(e) => {
setFile(e.target.files[0])
}}
/>
<div
className="buttonContainer"
onClick={() => {
setUploading(true)
uploadFile(currDir, file).then(() => {
setUploading(false)
setAddingNew(null)
getDir(currDir, true)
})
}}
>
<div>Feltöltés</div>
</div>
</>
) : (
<>
<SubjNameInput
uploading={uploading}
onChange={(e) => {
setNewSubjName(e)
}}
/>
<div
className="buttonContainer"
onClick={() => {
setUploading(true)
newSubj(newSubjName).then(() => {
setUploading(false)
setAddingNew(null)
getRootDir(true)
alert(`'${newSubjName}' létrehozva!`)
})
}}
>
<div>
{addingNew === 'file' ? 'OK' : 'Új mappa létrehozása'}
</div>
</div>
</>
)}
</div>
</Modal>
)}
</div>
)
}