diff --git a/package.json b/package.json index a43351d3..990d4f51 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "react-scripts": "5.0.1", "react-toastify": "9.1.1", "react-tooltip": "5.10.0", - "react-virtuoso": "4.3.2", + "react-virtuoso": "4.5.0", "rehype-sanitize": "5.0.1", "remark-breaks": "3.0.2", "styled-components": "5.3.9", @@ -120,7 +120,7 @@ } }, "devDependencies": { - "@babel/plugin-proposal-private-property-in-object": "7.21.11", + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@capacitor/cli": "3.6.0", "concurrently": "8.0.1", "cordova-res": "0.15.4", diff --git a/src/components/Post.jsx b/src/components/Post.jsx index 431c05f6..4d94e10c 100644 --- a/src/components/Post.jsx +++ b/src/components/Post.jsx @@ -6,7 +6,7 @@ import ForwardRefLink from './ForwardRefLink'; const Post = ({ content, postQuoteOnClick, postQuoteOnOver, postQuoteOnLeave, postQuoteRef }) => { - const doubleNewlineContent = useMemo(() => content?.replaceAll(/\n(?!\n)/g, '\n\n'), [content]); + const doubleNewlineContent = content?.replace(/\n/g, ' \n\n'); const customSchema = useMemo(() => ({ ...defaultSchema, diff --git a/src/components/modals/ModerationModal.jsx b/src/components/modals/ModerationModal.jsx index 9188516a..0c560045 100755 --- a/src/components/modals/ModerationModal.jsx +++ b/src/components/modals/ModerationModal.jsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from "react"; import Modal from "react-modal"; import { Link } from "react-router-dom"; -import { usePublishCommentEdit } from "@plebbit/plebbit-react-hooks"; +import { useComment, usePublishCommentEdit } from "@plebbit/plebbit-react-hooks"; import { StyledModal } from "../styled/modals/ModerationModal.styled"; import useGeneralStore from "../../hooks/stores/useGeneralStore"; import useError from "../../hooks/useError"; @@ -20,9 +20,11 @@ const ModerationModal = ({ isOpen, closeModal, deletePost }) => { setResolveCaptchaPromise, } = useGeneralStore(state => state); - const [pin, setPin] = useState(false); + const comment = useComment({commentCid: moderatingCommentCid}); + + const [pin, setPin] = useState(comment?.pinned); const [deleteThread, setDeleteThread] = useState(deletePost); - const [close, setClose] = useState(false); + const [close, setClose] = useState(comment?.locked); const [reason, setReason] = useState(''); const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false); diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx index 061a5c56..fceb7528 100755 --- a/src/components/modals/SettingsModal.jsx +++ b/src/components/modals/SettingsModal.jsx @@ -1,7 +1,6 @@ import React, { useState, useEffect, useRef } from "react"; import { Link, useLocation, useNavigate } from "react-router-dom"; import Modal from "react-modal"; -import { confirmAlert } from "react-confirm-alert"; import { deleteAccount, deleteCaches, exportAccount, importAccount, setAccount, setActiveAccount, useAccount, useAccounts, useResolvedAuthorAddress } from "@plebbit/plebbit-react-hooks"; import { StyledModal } from "../styled/modals/SettingsModal.styled"; import useError from "../../hooks/useError"; diff --git a/src/components/views/All.jsx b/src/components/views/All.jsx index 01a647c5..3bfee60e 100755 --- a/src/components/views/All.jsx +++ b/src/components/views/All.jsx @@ -29,6 +29,7 @@ import SettingsModal from '../modals/SettingsModal'; import findShortParentCid from '../../utils/findShortParentCid'; import getCommentMediaInfo from '../../utils/getCommentMediaInfo'; import getDate from '../../utils/getDate'; +import getFormattedTime from '../../utils/getFormattedTime'; import handleAddressClick from '../../utils/handleAddressClick'; import handleImageClick from '../../utils/handleImageClick'; import handleQuoteClick from '../../utils/handleQuoteClick'; @@ -851,7 +852,10 @@ const All = () => { {{({ shortAuthorAddress }) => (shortAuthorAddress)}} )   - {getDate(thread.timestamp)} + {getDate(thread.timestamp)}   c/ @@ -1179,7 +1183,10 @@ const All = () => {   - {getDate(reply.timestamp)} + {getDate(reply.timestamp)}   c/ @@ -1778,7 +1785,10 @@ const All = () => { tooltipPlace="top" className="offline-mobile-sub" /> - + {getDate(thread.timestamp)}   c/ @@ -2016,7 +2026,10 @@ const All = () => { tooltipPlace="top" className="offline-mobile-sub-reply" /> - + {getDate(reply.timestamp)}  c/ {reply.shortCid ? ( diff --git a/src/components/views/Board.jsx b/src/components/views/Board.jsx index 4c39ceec..15e82c62 100755 --- a/src/components/views/Board.jsx +++ b/src/components/views/Board.jsx @@ -30,6 +30,7 @@ import SettingsModal from '../modals/SettingsModal'; import findShortParentCid from '../../utils/findShortParentCid'; import getCommentMediaInfo from '../../utils/getCommentMediaInfo'; import getDate from '../../utils/getDate'; +import getFormattedTime from '../../utils/getFormattedTime'; import handleAddressClick from '../../utils/handleAddressClick'; import handleImageClick from '../../utils/handleImageClick'; import handleQuoteClick from '../../utils/handleQuoteClick'; @@ -786,6 +787,9 @@ const Board = () => { + {!defaultSubplebbits.some(subplebbit => subplebbit.address === selectedAddress) && ( + + )} {defaultSubplebbits.map(subplebbit => ( diff --git a/src/components/views/Description.jsx b/src/components/views/Description.jsx index c2af6868..19aa2605 100644 --- a/src/components/views/Description.jsx +++ b/src/components/views/Description.jsx @@ -28,7 +28,6 @@ const Description = () => { isSettingsOpen, setIsSettingsOpen, selectedAddress, setSelectedAddress, selectedStyle, - selectedThread, setSelectedTitle, } = useGeneralStore(state => state); @@ -181,7 +180,7 @@ const Description = () => { }>Create Board ] [ - setIsSettingsOpen(true)}>Settings + setIsSettingsOpen(true)}>Settings ] [ Home @@ -195,6 +194,9 @@ const Description = () => { + {!defaultSubplebbits.some(subplebbit => subplebbit.address === selectedAddress) && ( + + )} {defaultSubplebbits.map(subplebbit => ( diff --git a/src/components/views/Rules.jsx b/src/components/views/Rules.jsx index 78a98873..ecdb6952 100644 --- a/src/components/views/Rules.jsx +++ b/src/components/views/Rules.jsx @@ -26,7 +26,6 @@ const Rules = () => { isSettingsOpen, setIsSettingsOpen, selectedAddress, setSelectedAddress, selectedStyle, - selectedThread, setSelectedTitle, } = useGeneralStore(state => state); @@ -187,7 +186,7 @@ const Rules = () => { }>Create Board ] [ - setIsSettingsOpen(true)}>Settings + setIsSettingsOpen(true)}>Settings ] [ Home @@ -201,6 +200,9 @@ const Rules = () => { + {!defaultSubplebbits.some(subplebbit => subplebbit.address === selectedAddress) && ( + + )} {defaultSubplebbits.map(subplebbit => ( @@ -995,7 +999,12 @@ const Thread = () => { )   - {getDate(comment?.timestamp)} + + {getDate(comment?.timestamp)} +   c/ @@ -1292,7 +1301,10 @@ const Thread = () => {   - + {getDate(reply?.timestamp)}  c/ @@ -1747,7 +1759,10 @@ const Thread = () => { {comment.title} ) : null} - + {getDate(comment?.timestamp)}   c/ @@ -1940,7 +1955,10 @@ const Thread = () => {
- + {getDate(reply?.timestamp)}  c/ {reply.shortCid ? ( diff --git a/src/utils/getFormattedTime.js b/src/utils/getFormattedTime.js new file mode 100644 index 00000000..82545135 --- /dev/null +++ b/src/utils/getFormattedTime.js @@ -0,0 +1,39 @@ +const pluralize = (unit, value) => { + return `${value} ${unit}${value > 1 ? 's' : ''}`; +}; + +const getFormattedTime = (timestamp) => { + try { + const currentTime = new Date().getTime(); + const differenceInMilliseconds = currentTime - (timestamp * 1000); + + const years = Math.floor(differenceInMilliseconds / (1000 * 60 * 60 * 24 * 365.25)); + const months = Math.floor((differenceInMilliseconds % (1000 * 60 * 60 * 24 * 365.25)) / (1000 * 60 * 60 * 24 * 30)); + const days = Math.floor((differenceInMilliseconds % (1000 * 60 * 60 * 24 * 30)) / (1000 * 60 * 60 * 24)); + const hours = Math.floor((differenceInMilliseconds % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + const minutes = Math.floor((differenceInMilliseconds % (1000 * 60 * 60)) / (1000 * 60)); + const seconds = Math.floor((differenceInMilliseconds % (1000 * 60)) / 1000); + + if (years > 0) { + return months > 0 ? `${pluralize('year', years)} and ${pluralize('month', months)} ago` : `${pluralize('year', years)} ago`; + } else if (months > 0) { + return `${pluralize('month', months)} and ${pluralize('day', days)} ago`; + } else if (days > 0) { + return `${pluralize('day', days)} and ${pluralize('hour', hours)} ago`; + } else if (hours > 0) { + return `${pluralize('hour', hours)} and ${pluralize('minute', minutes)} ago`; + } else if (minutes > 0) { + return `${pluralize('minute', minutes)} and ${pluralize('second', seconds)} ago`; + } else if (seconds > 30) { + return `${pluralize('second', seconds)} ago`; + } else { + return "just now"; + } + } + catch (e) { + console.error("Error in getFormattedTime:", e); + return "[error]"; + } +}; + +export default getFormattedTime; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index ab7eeb01..62e757e4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -399,7 +399,7 @@ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== -"@babel/plugin-proposal-private-property-in-object@7.21.11": +"@babel/plugin-proposal-private-property-in-object@^7.21.11": version "7.21.11" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz#69d597086b6760c4126525cfa154f34631ff272c" integrity sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw== @@ -12496,10 +12496,10 @@ react-tooltip@5.10.0: "@floating-ui/dom" "1.2.3" classnames "^2.3.2" -react-virtuoso@4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.3.2.tgz#91d4926c67f635cf7efc2dea29e7cd6de83575d1" - integrity sha512-n51V4fMk36VM6NapfaMbfs4w/IaVodp5asp+rtzlvz0yurG6uVrqA040ke43gpYtoOL6j6TxeXWo4b6GpO9N0A== +react-virtuoso@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.5.0.tgz#0bc043b4e3e928e7891aa541dd7e55d5b46db8c8" + integrity sha512-OMP6XrzJMMos1vbJZC16RxGW7utAxUMP7i5PNPi6epBNVH7nz+CF/DlmecNBep5wyjLud51dQ5epjb2A0w9W/Q== react@18.2.0: version "18.2.0"