From 9c333008c7049b032e4e3d0dbf5fd5893542ffb7 Mon Sep 17 00:00:00 2001 From: mrfry Date: Mon, 16 May 2022 16:20:02 +0200 Subject: [PATCH] Mobile layout fixes, added user forum, modal scroll fix --- src/components/Question.js | 10 +- src/components/forum.js | 462 +++++++++++++++++++++++++++++++ src/components/forum.module.css | 97 +++++++ src/components/layout.module.css | 1 + src/components/modal.js | 2 + src/components/newsEntry.js | 2 + src/data/tabs.json | 6 +- src/defaultStyles.css | 7 +- src/pages/index.js | 354 ++--------------------- src/pages/index.module.css | 86 +----- src/pages/userForum.js | 29 ++ src/pages/userForum.module.css | 21 ++ 12 files changed, 649 insertions(+), 428 deletions(-) create mode 100644 src/components/forum.js create mode 100644 src/components/forum.module.css create mode 100644 src/pages/userForum.js create mode 100644 src/pages/userForum.module.css diff --git a/src/components/Question.js b/src/components/Question.js index 511caca..3a67325 100644 --- a/src/components/Question.js +++ b/src/components/Question.js @@ -34,14 +34,8 @@ export default function Question({ question, searchTerm }) { return (
-
-
+
{questionText}
+
{answerText}
{qdata || null}
) diff --git a/src/components/forum.js b/src/components/forum.js new file mode 100644 index 0000000..2baecce --- /dev/null +++ b/src/components/forum.js @@ -0,0 +1,462 @@ +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 + } + + if (error) { + return
Lil fuckup
+ } + + return ( + { + 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 ( + { + 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 ( +
+ {allowPost && ( + { + 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 && ( +
+ {'Feltöltés ...'} + +
+ )} +
{newsItems}
+ {nextEntryKey ? ( +
{ + 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 ? ( + + ) : ( + 'Több bejegyzés betöltése' + )} +
+ ) : ( +
+ {newsItems.length === 0 ? 'Üres fórum' : 'The end'} +
+ )} +
+ ) + } else { + return + } + } + + return ( +
+
+ + {children || null} + {renderNews()} + {postInModalKey && ( + { + setPostInModalKey(undefined) + router.replace(router.pathname, undefined, { shallow: true }) + }} + > + {news ? ( + + ) : ( + + )} + + )} +
+ ) +} diff --git a/src/components/forum.module.css b/src/components/forum.module.css new file mode 100644 index 0000000..af24549 --- /dev/null +++ b/src/components/forum.module.css @@ -0,0 +1,97 @@ +.hr { + width: 100%; +} + +.motd { + text-align: center; + font-size: 20px; + + border: 2px dashed var(--text-color); + padding-top: 13px; + padding-bottom: 15px; + padding-left: 5px; + padding-right: 5px; + margin-top: 18px; + margin-bottom: 30px; + margin-left: 5px; + margin-right: 5px; +} + +.itemContainer { + width: 100%; + margin: 20px 5px; + background-color: var(--hoover-color); +} + +.newsBody { + margin: 0px 5px; + padding: 10px 14px; + font-size: 17px; + color: #fff; + text-align: justify; +} + +.title { + color: var(--text-color); + font-size: 32px; + text-align: center; + letter-spacing: 2.5px; +} + +.subtitle { + color: var(--text-color); + font-size: 20px; + text-align: center; +} + +.newsTitle { + color: var(--text-color); + font-size: 28px; + padding-left: 17px; +} + +.question { + font-weight: bold; + font-size: 16px; + color: #fff; + margin: 0px 5px; +} + +.answer { + margin: 0px 5px; +} + +.itemNumber { + color: #a7a7a7; + margin: 0px 5px; + font-size: 22px; + padding-top: 12px; + padding-left: 13px; + padding-bottom: 3px; +} + +.repos { + display: flex; + flex-direction: column; +} + +.loadMoreButton { + display: flex; + justify-content: center; + align-items: center; + + background-color: var(--dark-color); + margin-left: 8px; + margin-right: 8px; + margin-bottom: 16px; + margin-top: 16px; + padding: 10px; + + height: 50px; + + cursor: pointer; +} + +.loadMoreButton:hover { + background-color: var(--hoover-color); +} diff --git a/src/components/layout.module.css b/src/components/layout.module.css index cfa5400..d488ead 100644 --- a/src/components/layout.module.css +++ b/src/components/layout.module.css @@ -98,6 +98,7 @@ @media screen and (max-width: 700px) { div.content { + max-width: calc(100vw); padding: 1px 0px; margin-left: 0; } diff --git a/src/components/modal.js b/src/components/modal.js index cc51083..53b1ca8 100644 --- a/src/components/modal.js +++ b/src/components/modal.js @@ -13,8 +13,10 @@ export default function Modal(props) { useEffect(() => { document.addEventListener('keydown', keyHandler) + document.body.classList.add('modal-open') return () => { document.removeEventListener('keydown', keyHandler) + document.body.classList.remove('modal-open') } }, []) diff --git a/src/components/newsEntry.js b/src/components/newsEntry.js index 4ac2a44..e9fb9d0 100644 --- a/src/components/newsEntry.js +++ b/src/components/newsEntry.js @@ -125,6 +125,8 @@ export default function NewsEntry({ {uid === user ? ( { + const res = window.confirm('Törlöd a bejegyzést?') + if (!res) return onPostDelete() }} > diff --git a/src/data/tabs.json b/src/data/tabs.json index 4dcf602..1a0f509 100644 --- a/src/data/tabs.json +++ b/src/data/tabs.json @@ -1,7 +1,11 @@ { "index": { "href": "/", - "text": "Főoldal" + "text": "Hírek" + }, + "userForum": { + "href": "/userForum", + "text": "Fórum" }, "script": { "href": "/script", diff --git a/src/defaultStyles.css b/src/defaultStyles.css index 031edd8..f1d226f 100644 --- a/src/defaultStyles.css +++ b/src/defaultStyles.css @@ -102,19 +102,16 @@ input:focus { } .question { - word-wrap: break-word; font-weight: bold; font-size: 17px; color: gainsboro; } .answer { - word-wrap: break-word; font-size: 15px; } .data { - word-wrap: break-word; font-size: 13px; color: #a1a1a1; } @@ -355,3 +352,7 @@ select:hover { font-weight: bold; color: var(--text-color); } + +.modal-open { + overflow: hidden; +} diff --git a/src/pages/index.js b/src/pages/index.js index 6db2eb8..57b98f6 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -1,331 +1,26 @@ -import React, { useState, useEffect } from 'react' -import fetch from 'unfetch' +import React from 'react' -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 Forum from '../components/forum' import styles from './index.module.css' -import constants from '../constants.json' -const forumPostPerPage = 5 -const frontpageForumName = 'frontpage' - -function fetchForum(from) { - return new Promise((resolve) => { - fetch( - `${ - constants.apiUrl - }forumEntries?forumName=${frontpageForumName}&getContent=true${ - from ? `&from=${from}` : '' - }&count=${forumPostPerPage}`, - { - credentials: 'include', - } - ) - .then((resp) => { - return resp.json() - }) - .then((res) => { - resolve(res) - }) - }) -} - -function addPost(title, content) { - return new Promise((resolve) => { - fetch(constants.apiUrl + 'addPost', { - method: 'POST', - credentials: 'include', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - forumName: frontpageForumName, - 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 - }, {}) -} - -export default function Main({ globalData, globalState, setGlobalState }) { - const userId = globalData.userId +export default function Index({ + router, + globalData, + globalState, + setGlobalState, +}) { const motd = globalData.motd - const [news, setNews] = useState(null) - const [nextEntryKey, setNextEntryKey] = useState() - const [fetchingForum, setFetchingForum] = useState(false) - useEffect(() => { - if (globalState.news) { - const { entries, nextKey } = globalState.news - setNextEntryKey(nextKey) - setNews(entries) - } else { - setFetchingForum(true) - fetchForum().then((res) => { - setFetchingForum(false) - const { entries, nextKey } = res - setNextEntryKey(nextKey) - setNews(entries) - setGlobalState({ news: res }) - }) - } - }, []) - - const renderNews = () => { - if (news) { - let newsItems = Object.keys(news).map((postKey) => { - let newsEntryData = news[postKey] - return ( - { - fetch(constants.apiUrl + 'rmPost', { - method: 'POST', - credentials: 'include', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - forumName: frontpageForumName, - 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: frontpageForumName, - }), - }) - .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: frontpageForumName, - }), - }) - .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: frontpageForumName, - }), - }) - .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: frontpageForumName, - }), - }) - .then((res) => { - return res.json() - }) - .then((res) => { - const { success, postData, msg } = res - if (success) { - setNews(updateForumPost(news, postKey, postData)) - } else { - alert(msg) - } - }) - }} - uid={userId} - key={postKey} - newsKey={postKey} - newsItem={newsEntryData} - /> - ) - }) - - return ( -
-
Fórum/Hírek
-
- { - addPost(title, content).then((res) => { - const { success, newPostKey, newEntry, msg } = res - if (success) { - setNews({ [newPostKey]: newEntry, ...news }) - } else { - alert(msg) - } - }) - }} - /> -
{newsItems}
- {nextEntryKey ? ( -
{ - if (fetchingForum) { - return - } - - setFetchingForum(true) - fetchForum(nextEntryKey).then((res) => { - setFetchingForum(false) - - const { entries, nextKey } = res - setNextEntryKey(nextKey) - setNews({ ...news, ...entries }) - setGlobalState({ - news: { - entries: { ...news, ...entries }, - nextKey: nextKey, - }, - }) - }) - }} - > - {fetchingForum ? ( - - ) : ( - 'Több bejegyzés betöltése' - )} -
- ) : ( -
- {'The end'} -
- )} -
- ) - } else { - return - } - } - - const renderMotd = () => { - if (motd) { - return ( + return ( + + {motd && (
MOTD
{motd ? ( @@ -334,18 +29,7 @@ export default function Main({ globalData, globalState, setGlobalState }) {
...
)}
- ) - } else { - return null - } - } - - return ( -
-
- {renderMotd()} - - {renderNews()} -
+ )} +
) } diff --git a/src/pages/index.module.css b/src/pages/index.module.css index af24549..8a5e7d3 100644 --- a/src/pages/index.module.css +++ b/src/pages/index.module.css @@ -1,5 +1,8 @@ -.hr { - width: 100%; +.title { + color: var(--text-color); + font-size: 32px; + text-align: center; + letter-spacing: 2.5px; } .motd { @@ -16,82 +19,3 @@ margin-left: 5px; margin-right: 5px; } - -.itemContainer { - width: 100%; - margin: 20px 5px; - background-color: var(--hoover-color); -} - -.newsBody { - margin: 0px 5px; - padding: 10px 14px; - font-size: 17px; - color: #fff; - text-align: justify; -} - -.title { - color: var(--text-color); - font-size: 32px; - text-align: center; - letter-spacing: 2.5px; -} - -.subtitle { - color: var(--text-color); - font-size: 20px; - text-align: center; -} - -.newsTitle { - color: var(--text-color); - font-size: 28px; - padding-left: 17px; -} - -.question { - font-weight: bold; - font-size: 16px; - color: #fff; - margin: 0px 5px; -} - -.answer { - margin: 0px 5px; -} - -.itemNumber { - color: #a7a7a7; - margin: 0px 5px; - font-size: 22px; - padding-top: 12px; - padding-left: 13px; - padding-bottom: 3px; -} - -.repos { - display: flex; - flex-direction: column; -} - -.loadMoreButton { - display: flex; - justify-content: center; - align-items: center; - - background-color: var(--dark-color); - margin-left: 8px; - margin-right: 8px; - margin-bottom: 16px; - margin-top: 16px; - padding: 10px; - - height: 50px; - - cursor: pointer; -} - -.loadMoreButton:hover { - background-color: var(--hoover-color); -} diff --git a/src/pages/userForum.js b/src/pages/userForum.js new file mode 100644 index 0000000..579e19a --- /dev/null +++ b/src/pages/userForum.js @@ -0,0 +1,29 @@ +import React from 'react' + +import Forum from '../components/forum' + +import styles from './userForum.module.css' + +export default function UserForum({ + router, + globalData, + globalState, + setGlobalState, +}) { + return ( + +
+
Felhasználói fórum
+ Itt lehet témákat felvetni és megbeszélni a többi felhasználóval, vagy + adminnal. +
+
+ ) +} diff --git a/src/pages/userForum.module.css b/src/pages/userForum.module.css new file mode 100644 index 0000000..2ecd39b --- /dev/null +++ b/src/pages/userForum.module.css @@ -0,0 +1,21 @@ +.topMsg { + text-align: center; + font-size: 18px; + + border: 2px dashed var(--text-color); + padding-top: 13px; + padding-bottom: 15px; + padding-left: 5px; + padding-right: 5px; + margin-top: 18px; + margin-bottom: 30px; + margin-left: 5px; + margin-right: 5px; +} + +.title { + color: var(--text-color); + font-size: 32px; + text-align: center; + letter-spacing: 2.5px; +}