mirror of
				https://gitlab.com/MrFry/qmining-page
				synced 2025-04-01 20:23:44 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			463 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			463 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import React, { useState, useEffect } from 'react'
 | |
| import fetch from 'unfetch'
 | |
| 
 | |
| import LoadingIndicator from '../components/LoadingIndicator'
 | |
| import Sleep from '../components/sleep'
 | |
| import NewsEntry from '../components/newsEntry'
 | |
| import Composer from '../components/composer'
 | |
| import Header from '../components/header'
 | |
| import Modal from '../components/modal'
 | |
| 
 | |
| import styles from './forum.module.css'
 | |
| import constants from '../constants.json'
 | |
| 
 | |
| const forumPostPerPage = 5
 | |
| 
 | |
| function fetchEntry(postKey, forumName) {
 | |
|   return new Promise((resolve) => {
 | |
|     fetch(
 | |
|       `${constants.apiUrl}forumEntry?forumName=${forumName}&postKey=${postKey}`,
 | |
|       {
 | |
|         credentials: 'include',
 | |
|       }
 | |
|     )
 | |
|       .then((resp) => {
 | |
|         return resp.json()
 | |
|       })
 | |
|       .then((res) => {
 | |
|         resolve(res)
 | |
|       })
 | |
|   })
 | |
| }
 | |
| 
 | |
| function fetchForum(forumName, from) {
 | |
|   return new Promise((resolve) => {
 | |
|     fetch(
 | |
|       `${constants.apiUrl}forumEntries?forumName=${forumName}&getContent=true${
 | |
|         from ? `&from=${from}` : ''
 | |
|       }&count=${forumPostPerPage}`,
 | |
|       {
 | |
|         credentials: 'include',
 | |
|       }
 | |
|     )
 | |
|       .then((resp) => {
 | |
|         return resp.json()
 | |
|       })
 | |
|       .then((res) => {
 | |
|         resolve(res)
 | |
|       })
 | |
|   })
 | |
| }
 | |
| 
 | |
| function addPost(title, content, forumName) {
 | |
|   return new Promise((resolve) => {
 | |
|     fetch(constants.apiUrl + 'addPost', {
 | |
|       method: 'POST',
 | |
|       credentials: 'include',
 | |
|       headers: {
 | |
|         Accept: 'application/json',
 | |
|         'Content-Type': 'application/json',
 | |
|       },
 | |
|       body: JSON.stringify({
 | |
|         forumName: forumName,
 | |
|         title: title,
 | |
|         content: content,
 | |
|       }),
 | |
|     })
 | |
|       .then((res) => {
 | |
|         return res.json()
 | |
|       })
 | |
|       .then((res) => {
 | |
|         resolve(res)
 | |
|       })
 | |
|   })
 | |
| }
 | |
| 
 | |
| function updateForumPost(forum, postKey, postData) {
 | |
|   return Object.keys(forum).reduce((acc, key) => {
 | |
|     const entry = forum[key]
 | |
|     if (key === postKey) {
 | |
|       acc = {
 | |
|         ...acc,
 | |
|         [key]: postData,
 | |
|       }
 | |
|     } else {
 | |
|       acc = {
 | |
|         ...acc,
 | |
|         [key]: entry,
 | |
|       }
 | |
|     }
 | |
|     return acc
 | |
|   }, {})
 | |
| }
 | |
| 
 | |
| const NewsEntryContainer = ({
 | |
|   postKey,
 | |
|   setNews,
 | |
|   news,
 | |
|   userId,
 | |
|   newsEntryData,
 | |
|   onTitleClick,
 | |
|   forumName,
 | |
| }) => {
 | |
|   const [error, setError] = useState(false)
 | |
| 
 | |
|   useEffect(() => {
 | |
|     if (!newsEntryData && !error) {
 | |
|       fetchEntry(postKey, forumName)
 | |
|         .then((res) => {
 | |
|           const { success, entry, msg } = res
 | |
|           if (success) {
 | |
|             setNews({ [postKey]: entry, ...news })
 | |
|           } else {
 | |
|             alert(msg)
 | |
|             setError(true)
 | |
|           }
 | |
|         })
 | |
|         .catch((e) => {
 | |
|           console.error(e)
 | |
|           setError(true)
 | |
|         })
 | |
|     }
 | |
|   }, [])
 | |
| 
 | |
|   if (!newsEntryData) {
 | |
|     return <LoadingIndicator />
 | |
|   }
 | |
| 
 | |
|   if (error) {
 | |
|     return <div>Lil fuckup</div>
 | |
|   }
 | |
| 
 | |
|   return (
 | |
|     <NewsEntry
 | |
|       onTitleClick={onTitleClick}
 | |
|       uid={userId}
 | |
|       key={postKey}
 | |
|       newsKey={postKey}
 | |
|       newsItem={newsEntryData}
 | |
|       onPostDelete={() => {
 | |
|         fetch(constants.apiUrl + 'rmPost', {
 | |
|           method: 'POST',
 | |
|           credentials: 'include',
 | |
|           headers: {
 | |
|             Accept: 'application/json',
 | |
|             'Content-Type': 'application/json',
 | |
|           },
 | |
|           body: JSON.stringify({
 | |
|             forumName: forumName,
 | |
|             postKey: postKey,
 | |
|           }),
 | |
|         })
 | |
|           .then((res) => {
 | |
|             return res.json()
 | |
|           })
 | |
|           .then((res) => {
 | |
|             const { success, msg } = res
 | |
|             if (success) {
 | |
|               setNews(
 | |
|                 Object.keys(news).reduce((acc, key) => {
 | |
|                   const entry = news[key]
 | |
|                   if (key !== postKey) {
 | |
|                     acc = {
 | |
|                       ...acc,
 | |
|                       [key]: entry,
 | |
|                     }
 | |
|                   }
 | |
|                   return acc
 | |
|                 }, {})
 | |
|               )
 | |
|             } else {
 | |
|               alert(msg)
 | |
|             }
 | |
|           })
 | |
|       }}
 | |
|       onNewsReact={({ reaction, isDelete }) => {
 | |
|         fetch(constants.apiUrl + 'react', {
 | |
|           method: 'POST',
 | |
|           credentials: 'include',
 | |
|           headers: {
 | |
|             Accept: 'application/json',
 | |
|             'Content-Type': 'application/json',
 | |
|           },
 | |
|           body: JSON.stringify({
 | |
|             reaction: reaction,
 | |
|             postKey: postKey,
 | |
|             isDelete: isDelete,
 | |
|             forumName: forumName,
 | |
|           }),
 | |
|         })
 | |
|           .then((res) => {
 | |
|             return res.json()
 | |
|           })
 | |
|           .then((res) => {
 | |
|             setNews(updateForumPost(news, postKey, res.postData))
 | |
|           })
 | |
|       }}
 | |
|       onCommentReact={({ path, reaction, isDelete }) => {
 | |
|         fetch(constants.apiUrl + 'react', {
 | |
|           method: 'POST',
 | |
|           credentials: 'include',
 | |
|           headers: {
 | |
|             Accept: 'application/json',
 | |
|             'Content-Type': 'application/json',
 | |
|           },
 | |
|           body: JSON.stringify({
 | |
|             type: 'reaction',
 | |
|             postKey: postKey,
 | |
|             path: path,
 | |
|             reaction: reaction,
 | |
|             isDelete: isDelete,
 | |
|             forumName: forumName,
 | |
|           }),
 | |
|         })
 | |
|           .then((res) => {
 | |
|             return res.json()
 | |
|           })
 | |
|           .then((res) => {
 | |
|             const { success, postData, msg } = res
 | |
|             if (success) {
 | |
|               setNews(updateForumPost(news, postKey, postData))
 | |
|             } else {
 | |
|               alert(msg)
 | |
|             }
 | |
|           })
 | |
|       }}
 | |
|       onDelete={(path) => {
 | |
|         fetch(constants.apiUrl + 'comment', {
 | |
|           method: 'POST',
 | |
|           credentials: 'include',
 | |
|           headers: {
 | |
|             Accept: 'application/json',
 | |
|             'Content-Type': 'application/json',
 | |
|           },
 | |
|           body: JSON.stringify({
 | |
|             type: 'delete',
 | |
|             path: path,
 | |
|             postKey: postKey,
 | |
|             forumName: forumName,
 | |
|           }),
 | |
|         })
 | |
|           .then((res) => {
 | |
|             return res.json()
 | |
|           })
 | |
|           .then((res) => {
 | |
|             const { success, postData, msg } = res
 | |
|             if (success) {
 | |
|               setNews(updateForumPost(news, postKey, postData))
 | |
|             } else {
 | |
|               alert(msg)
 | |
|             }
 | |
|           })
 | |
|       }}
 | |
|       onComment={(path, content) => {
 | |
|         fetch(constants.apiUrl + 'comment', {
 | |
|           method: 'POST',
 | |
|           credentials: 'include',
 | |
|           headers: {
 | |
|             Accept: 'application/json',
 | |
|             'Content-Type': 'application/json',
 | |
|           },
 | |
|           body: JSON.stringify({
 | |
|             type: 'add',
 | |
|             path: path,
 | |
|             content: content,
 | |
|             postKey: postKey,
 | |
|             forumName: forumName,
 | |
|           }),
 | |
|         })
 | |
|           .then((res) => {
 | |
|             return res.json()
 | |
|           })
 | |
|           .then((res) => {
 | |
|             const { success, postData, msg } = res
 | |
|             if (success) {
 | |
|               setNews(updateForumPost(news, postKey, postData))
 | |
|             } else {
 | |
|               alert(msg)
 | |
|             }
 | |
|           })
 | |
|       }}
 | |
|     />
 | |
|   )
 | |
| }
 | |
| 
 | |
| export default function Forum({
 | |
|   router,
 | |
|   globalData,
 | |
|   globalState,
 | |
|   setGlobalState,
 | |
|   forumName,
 | |
|   children,
 | |
|   allowPost,
 | |
| }) {
 | |
|   const userId = globalData.userId
 | |
|   const [news, setNews] = useState(null)
 | |
|   const [nextEntryKey, setNextEntryKey] = useState()
 | |
|   const [fetchingForum, setFetchingForum] = useState(false)
 | |
|   const [postInModalKey, setPostInModalKey] = useState()
 | |
|   const [isUploading, setIsUploading] = useState(false)
 | |
| 
 | |
|   useEffect(() => {
 | |
|     if (globalState[forumName]) {
 | |
|       const { entries, nextKey } = globalState[forumName]
 | |
|       setNextEntryKey(nextKey)
 | |
|       setNews(entries)
 | |
|     } else {
 | |
|       setFetchingForum(true)
 | |
|       fetchForum(forumName).then((res) => {
 | |
|         setFetchingForum(false)
 | |
|         const { entries, nextKey } = res
 | |
|         setNextEntryKey(nextKey)
 | |
|         setNews(entries)
 | |
|         setGlobalState({ [forumName]: res })
 | |
|       })
 | |
|     }
 | |
|   }, [])
 | |
| 
 | |
|   useEffect(() => {
 | |
|     const postKey = router.query.postKey
 | |
|       ? decodeURIComponent(router.query.postKey)
 | |
|       : ''
 | |
| 
 | |
|     if (postKey) {
 | |
|       setPostInModalKey(postKey)
 | |
|     }
 | |
|   }, [router.query.postKey])
 | |
| 
 | |
|   const renderNews = () => {
 | |
|     if (news) {
 | |
|       const newsItems = Object.keys(news).map((postKey) => {
 | |
|         const newsEntryData = news[postKey]
 | |
|         return (
 | |
|           <NewsEntryContainer
 | |
|             forumName={forumName}
 | |
|             onTitleClick={() => {
 | |
|               setPostInModalKey(postKey)
 | |
|               router.replace(
 | |
|                 `${router.pathname}?postKey=${encodeURIComponent(postKey)}`,
 | |
|                 undefined,
 | |
|                 { shallow: true }
 | |
|               )
 | |
|             }}
 | |
|             key={postKey}
 | |
|             postKey={postKey}
 | |
|             setNews={setNews}
 | |
|             news={news}
 | |
|             userId={userId}
 | |
|             newsEntryData={newsEntryData}
 | |
|           />
 | |
|         )
 | |
|       })
 | |
| 
 | |
|       return (
 | |
|         <div>
 | |
|           {allowPost && (
 | |
|             <Composer
 | |
|               onSubmit={(title, content) => {
 | |
|                 setIsUploading(true)
 | |
| 
 | |
|                 addPost(title, content, forumName).then((res) => {
 | |
|                   const { success, newPostKey, newEntry, msg } = res
 | |
|                   if (success) {
 | |
|                     setNews({ [newPostKey]: newEntry, ...news })
 | |
|                   } else {
 | |
|                     alert(msg)
 | |
|                   }
 | |
|                   setIsUploading(false)
 | |
|                 })
 | |
|               }}
 | |
|             />
 | |
|           )}
 | |
|           {isUploading && (
 | |
|             <div
 | |
|               style={{
 | |
|                 display: 'flex',
 | |
|                 alignItems: 'center',
 | |
|                 flexDirection: 'column',
 | |
|               }}
 | |
|             >
 | |
|               {'Feltöltés ...'}
 | |
|               <LoadingIndicator />
 | |
|             </div>
 | |
|           )}
 | |
|           <div>{newsItems}</div>
 | |
|           {nextEntryKey ? (
 | |
|             <div
 | |
|               className={styles.loadMoreButton}
 | |
|               onClick={() => {
 | |
|                 if (fetchingForum) {
 | |
|                   return
 | |
|                 }
 | |
| 
 | |
|                 setFetchingForum(true)
 | |
|                 fetchForum(forumName, nextEntryKey).then((res) => {
 | |
|                   setFetchingForum(false)
 | |
| 
 | |
|                   const { entries, nextKey } = res
 | |
|                   setNextEntryKey(nextKey)
 | |
|                   setNews({ ...news, ...entries })
 | |
|                   setGlobalState({
 | |
|                     news: {
 | |
|                       entries: { ...news, ...entries },
 | |
|                       nextKey: nextKey,
 | |
|                     },
 | |
|                   })
 | |
|                 })
 | |
|               }}
 | |
|             >
 | |
|               {fetchingForum ? (
 | |
|                 <LoadingIndicator />
 | |
|               ) : (
 | |
|                 'Több bejegyzés betöltése'
 | |
|               )}
 | |
|             </div>
 | |
|           ) : (
 | |
|             <div
 | |
|               style={{
 | |
|                 padding: 16,
 | |
|                 display: 'flex',
 | |
|                 justifyContent: 'center',
 | |
|                 fontStyle: 'italic',
 | |
|               }}
 | |
|             >
 | |
|               {newsItems.length === 0 ? 'Üres fórum' : 'The end'}
 | |
|             </div>
 | |
|           )}
 | |
|         </div>
 | |
|       )
 | |
|     } else {
 | |
|       return <LoadingIndicator />
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return (
 | |
|     <div>
 | |
|       <Header />
 | |
|       <Sleep />
 | |
|       {children || null}
 | |
|       {renderNews()}
 | |
|       {postInModalKey && (
 | |
|         <Modal
 | |
|           closeClick={() => {
 | |
|             setPostInModalKey(undefined)
 | |
|             router.replace(router.pathname, undefined, { shallow: true })
 | |
|           }}
 | |
|         >
 | |
|           {news ? (
 | |
|             <NewsEntryContainer
 | |
|               postKey={postInModalKey}
 | |
|               setNews={setNews}
 | |
|               news={news}
 | |
|               userId={userId}
 | |
|               newsEntryData={news[postInModalKey]}
 | |
|             />
 | |
|           ) : (
 | |
|             <LoadingIndicator />
 | |
|           )}
 | |
|         </Modal>
 | |
|       )}
 | |
|     </div>
 | |
|   )
 | |
| }
 |