diff --git a/frontend/packages/kitconcept-intranet/locales/de/LC_MESSAGES/volto.po b/frontend/packages/kitconcept-intranet/locales/de/LC_MESSAGES/volto.po index 4f5650cfe..aeafdf498 100644 --- a/frontend/packages/kitconcept-intranet/locales/de/LC_MESSAGES/volto.po +++ b/frontend/packages/kitconcept-intranet/locales/de/LC_MESSAGES/volto.po @@ -26,6 +26,11 @@ msgstr "KI-generierte Antwort. Kann Fehler enthalten." msgid "About this content" msgstr "Über diesen Inhalt" +#. Default: "Add comment... (@ mention a person)" +#: components/Comments/messages +msgid "Add comment... (@ mention a person)" +msgstr "Kommentar hinzufügen... (@ erwähnt eine Person)" + #. Default: "Address" #: components/theme/PersonView msgid "Address" @@ -104,6 +109,11 @@ msgstr "Abbrechen" msgid "Comment" msgstr "Kommentar:" +#. Default: "Comments" +#: components/Comments/messages +msgid "Comments" +msgstr "Kommentare" + #. Default: "Contact" #: components/Blocks/EventMetadata/View #: components/theme/PersonView @@ -150,6 +160,11 @@ msgstr "Prüfung/Anpassung delegieren" msgid "DelegateButton" msgstr "Delegieren" +#. Default: "Delete" +#: components/Comments/messages +msgid "Delete" +msgstr "Löschen" + #. Default: "Depth" #: components/widgets/QuerystringWidget msgid "Depth" @@ -167,6 +182,11 @@ msgstr "Review dokumentieren" msgid "E-mail" msgstr "E-mail" +#. Default: "Edit" +#: components/Comments/messages +msgid "Edit" +msgstr "Bearbeiten" + #. Default: "Email" #: components/FeedBackForm/FeedBackForm msgid "Email" @@ -438,6 +458,11 @@ msgstr "Privat" msgid "Published" msgstr "Veröffentlicht" +#. Default: "Reply" +#: components/Comments/messages +msgid "Reply" +msgstr "Antworten" + #. Default: "Responsibilities" #: index msgid "Responsibilities" @@ -500,6 +525,11 @@ msgstr "Suchen…" msgid "SelectAssigneePlaceholder" msgstr "Bitte auswählen ..." +#. Default: "Send comment" +#: components/Comments/messages +msgid "Send comment" +msgstr "Kommentar senden" + #. Default: "Send feedback" #: components/FeedBackForm/FeedBackForm #: slots/AboutThisContent/AboutThisContent @@ -629,6 +659,11 @@ msgstr "Aktualisiert" msgid "Use preset review interval" msgstr "Voreingestelltes Überprüfungsintervall verwenden." +#. Default: "Visible to everyone who can see this page." +#: components/Comments/messages +msgid "Visible to everyone who can see this page." +msgstr "Für alle sichtbar, die diese Seite sehen können." + #. Default: "Website" #: components/Blocks/EventMetadata/View msgid "Website" diff --git a/frontend/packages/kitconcept-intranet/locales/en/LC_MESSAGES/volto.po b/frontend/packages/kitconcept-intranet/locales/en/LC_MESSAGES/volto.po index 2bc8afe42..87670dd3b 100644 --- a/frontend/packages/kitconcept-intranet/locales/en/LC_MESSAGES/volto.po +++ b/frontend/packages/kitconcept-intranet/locales/en/LC_MESSAGES/volto.po @@ -26,6 +26,11 @@ msgstr "" msgid "About this content" msgstr "" +#. Default: "Add comment... (@ mention a person)" +#: components/Comments/messages +msgid "Add comment... (@ mention a person)" +msgstr "" + #. Default: "Address" #: components/theme/PersonView msgid "Address" @@ -104,6 +109,11 @@ msgstr "" msgid "Comment" msgstr "" +#. Default: "Comments" +#: components/Comments/messages +msgid "Comments" +msgstr "" + #. Default: "Contact" #: components/Blocks/EventMetadata/View #: components/theme/PersonView @@ -150,6 +160,11 @@ msgstr "" msgid "DelegateButton" msgstr "" +#. Default: "Delete" +#: components/Comments/messages +msgid "Delete" +msgstr "" + #. Default: "Depth" #: components/widgets/QuerystringWidget msgid "Depth" @@ -167,6 +182,11 @@ msgstr "" msgid "E-mail" msgstr "E-mail" +#. Default: "Edit" +#: components/Comments/messages +msgid "Edit" +msgstr "" + #. Default: "Email" #: components/FeedBackForm/FeedBackForm msgid "Email" @@ -438,6 +458,11 @@ msgstr "" msgid "Published" msgstr "" +#. Default: "Reply" +#: components/Comments/messages +msgid "Reply" +msgstr "" + #. Default: "Responsibilities" #: index msgid "Responsibilities" @@ -500,6 +525,11 @@ msgstr "" msgid "SelectAssigneePlaceholder" msgstr "" +#. Default: "Send comment" +#: components/Comments/messages +msgid "Send comment" +msgstr "" + #. Default: "Send feedback" #: components/FeedBackForm/FeedBackForm #: slots/AboutThisContent/AboutThisContent @@ -629,6 +659,11 @@ msgstr "" msgid "Use preset review interval" msgstr "" +#. Default: "Visible to everyone who can see this page." +#: components/Comments/messages +msgid "Visible to everyone who can see this page." +msgstr "" + #. Default: "Website" #: components/Blocks/EventMetadata/View msgid "Website" diff --git a/frontend/packages/kitconcept-intranet/locales/es/LC_MESSAGES/volto.po b/frontend/packages/kitconcept-intranet/locales/es/LC_MESSAGES/volto.po index fc0826d90..fa3012dc1 100644 --- a/frontend/packages/kitconcept-intranet/locales/es/LC_MESSAGES/volto.po +++ b/frontend/packages/kitconcept-intranet/locales/es/LC_MESSAGES/volto.po @@ -33,6 +33,11 @@ msgstr "" msgid "About this content" msgstr "" +#. Default: "Add comment... (@ mention a person)" +#: components/Comments/messages +msgid "Add comment... (@ mention a person)" +msgstr "" + #. Default: "Address" #: components/theme/PersonView msgid "Address" @@ -111,6 +116,11 @@ msgstr "" msgid "Comment" msgstr "" +#. Default: "Comments" +#: components/Comments/messages +msgid "Comments" +msgstr "" + #. Default: "Contact" #: components/Blocks/EventMetadata/View #: components/theme/PersonView @@ -157,6 +167,11 @@ msgstr "" msgid "DelegateButton" msgstr "" +#. Default: "Delete" +#: components/Comments/messages +msgid "Delete" +msgstr "" + #. Default: "Depth" #: components/widgets/QuerystringWidget msgid "Depth" @@ -174,6 +189,11 @@ msgstr "" msgid "E-mail" msgstr "" +#. Default: "Edit" +#: components/Comments/messages +msgid "Edit" +msgstr "" + #. Default: "Email" #: components/FeedBackForm/FeedBackForm msgid "Email" @@ -445,6 +465,11 @@ msgstr "" msgid "Published" msgstr "" +#. Default: "Reply" +#: components/Comments/messages +msgid "Reply" +msgstr "" + #. Default: "Responsibilities" #: index msgid "Responsibilities" @@ -507,6 +532,11 @@ msgstr "" msgid "SelectAssigneePlaceholder" msgstr "" +#. Default: "Send comment" +#: components/Comments/messages +msgid "Send comment" +msgstr "" + #. Default: "Send feedback" #: components/FeedBackForm/FeedBackForm #: slots/AboutThisContent/AboutThisContent @@ -636,6 +666,11 @@ msgstr "" msgid "Use preset review interval" msgstr "" +#. Default: "Visible to everyone who can see this page." +#: components/Comments/messages +msgid "Visible to everyone who can see this page." +msgstr "" + #. Default: "Website" #: components/Blocks/EventMetadata/View msgid "Website" diff --git a/frontend/packages/kitconcept-intranet/locales/pt_BR/LC_MESSAGES/volto.po b/frontend/packages/kitconcept-intranet/locales/pt_BR/LC_MESSAGES/volto.po index 19f625101..9ed643ed3 100644 --- a/frontend/packages/kitconcept-intranet/locales/pt_BR/LC_MESSAGES/volto.po +++ b/frontend/packages/kitconcept-intranet/locales/pt_BR/LC_MESSAGES/volto.po @@ -31,6 +31,11 @@ msgstr "" msgid "About this content" msgstr "" +#. Default: "Add comment... (@ mention a person)" +#: components/Comments/messages +msgid "Add comment... (@ mention a person)" +msgstr "" + #. Default: "Address" #: components/theme/PersonView msgid "Address" @@ -109,6 +114,11 @@ msgstr "" msgid "Comment" msgstr "" +#. Default: "Comments" +#: components/Comments/messages +msgid "Comments" +msgstr "" + #. Default: "Contact" #: components/Blocks/EventMetadata/View #: components/theme/PersonView @@ -155,6 +165,11 @@ msgstr "" msgid "DelegateButton" msgstr "" +#. Default: "Delete" +#: components/Comments/messages +msgid "Delete" +msgstr "" + #. Default: "Depth" #: components/widgets/QuerystringWidget msgid "Depth" @@ -172,6 +187,11 @@ msgstr "" msgid "E-mail" msgstr "E-mail" +#. Default: "Edit" +#: components/Comments/messages +msgid "Edit" +msgstr "" + #. Default: "Email" #: components/FeedBackForm/FeedBackForm msgid "Email" @@ -443,6 +463,11 @@ msgstr "" msgid "Published" msgstr "" +#. Default: "Reply" +#: components/Comments/messages +msgid "Reply" +msgstr "" + #. Default: "Responsibilities" #: index msgid "Responsibilities" @@ -505,6 +530,11 @@ msgstr "" msgid "SelectAssigneePlaceholder" msgstr "" +#. Default: "Send comment" +#: components/Comments/messages +msgid "Send comment" +msgstr "" + #. Default: "Send feedback" #: components/FeedBackForm/FeedBackForm #: slots/AboutThisContent/AboutThisContent @@ -634,6 +664,11 @@ msgstr "" msgid "Use preset review interval" msgstr "" +#. Default: "Visible to everyone who can see this page." +#: components/Comments/messages +msgid "Visible to everyone who can see this page." +msgstr "" + #. Default: "Website" #: components/Blocks/EventMetadata/View msgid "Website" diff --git a/frontend/packages/kitconcept-intranet/locales/volto.pot b/frontend/packages/kitconcept-intranet/locales/volto.pot index 48f476f6d..b30028097 100644 --- a/frontend/packages/kitconcept-intranet/locales/volto.pot +++ b/frontend/packages/kitconcept-intranet/locales/volto.pot @@ -28,6 +28,11 @@ msgstr "" msgid "About this content" msgstr "" +#. Default: "Add comment... (@ mention a person)" +#: components/Comments/messages +msgid "Add comment... (@ mention a person)" +msgstr "" + #. Default: "Address" #: components/theme/PersonView msgid "Address" @@ -106,6 +111,11 @@ msgstr "" msgid "Comment" msgstr "" +#. Default: "Comments" +#: components/Comments/messages +msgid "Comments" +msgstr "" + #. Default: "Contact" #: components/Blocks/EventMetadata/View #: components/theme/PersonView @@ -152,6 +162,11 @@ msgstr "" msgid "DelegateButton" msgstr "" +#. Default: "Delete" +#: components/Comments/messages +msgid "Delete" +msgstr "" + #. Default: "Depth" #: components/widgets/QuerystringWidget msgid "Depth" @@ -169,6 +184,11 @@ msgstr "" msgid "E-mail" msgstr "" +#. Default: "Edit" +#: components/Comments/messages +msgid "Edit" +msgstr "" + #. Default: "Email" #: components/FeedBackForm/FeedBackForm msgid "Email" @@ -440,6 +460,11 @@ msgstr "" msgid "Published" msgstr "" +#. Default: "Reply" +#: components/Comments/messages +msgid "Reply" +msgstr "" + #. Default: "Responsibilities" #: index msgid "Responsibilities" @@ -502,6 +527,11 @@ msgstr "" msgid "SelectAssigneePlaceholder" msgstr "" +#. Default: "Send comment" +#: components/Comments/messages +msgid "Send comment" +msgstr "" + #. Default: "Send feedback" #: components/FeedBackForm/FeedBackForm #: slots/AboutThisContent/AboutThisContent @@ -631,6 +661,11 @@ msgstr "" msgid "Use preset review interval" msgstr "" +#. Default: "Visible to everyone who can see this page." +#: components/Comments/messages +msgid "Visible to everyone who can see this page." +msgstr "" + #. Default: "Website" #: components/Blocks/EventMetadata/View msgid "Website" diff --git a/frontend/packages/kitconcept-intranet/news/469.feature b/frontend/packages/kitconcept-intranet/news/469.feature new file mode 100644 index 000000000..b478b83ae --- /dev/null +++ b/frontend/packages/kitconcept-intranet/news/469.feature @@ -0,0 +1 @@ +Update comments layout, styling, and footer placement @iRohitSingh \ No newline at end of file diff --git a/frontend/packages/kitconcept-intranet/src/components/ContentInteractions/ContentInteractions.jsx b/frontend/packages/kitconcept-intranet/src/components/ContentInteractions/ContentInteractions.jsx index 3ef3b8033..30100eb46 100644 --- a/frontend/packages/kitconcept-intranet/src/components/ContentInteractions/ContentInteractions.jsx +++ b/frontend/packages/kitconcept-intranet/src/components/ContentInteractions/ContentInteractions.jsx @@ -9,7 +9,11 @@ import { defineMessages, useIntl } from 'react-intl'; import { toast } from 'react-toastify'; import Toast from '@plone/volto/components/manage/Toast/Toast'; import { toggleLike } from '../../actions/likes/likes'; -import { flattenToAppURL } from '@plone/volto/helpers/Url/Url'; +import { + flattenToAppURL, + getBaseUrl, + isCmsUi, +} from '@plone/volto/helpers/Url/Url'; import thumbsSVG from '../../icons/icon-thumbs.svg'; import thumbsFilledSVG from '../../icons/icon-thumbs-filled.svg'; import commentSVG from '../../icons/comment.svg'; @@ -76,10 +80,19 @@ const ContentInteractions = (props) => { const intl = useIntl(); const flattenPathname = flattenToAppURL(pathname); const dispatch = useDispatch(); - const comment_count = useSelector( + const storedCommentCount = useSelector( (state) => state.comments.items_total, shallowEqual, ); + const commentsLoading = useSelector( + (state) => state.comments.list.loading, + shallowEqual, + ); + const contentPath = flattenToAppURL(content?.['@id']); + const isCurrentContent = + !isCmsUi(pathname) && contentPath === getBaseUrl(pathname); + const comment_count = + isCurrentContent && !commentsLoading ? storedCommentCount : 0; const [amount, setAmount] = useState(votes ? parseInt(votes.length) : 0); const [liked, setLiked] = useState(false); diff --git a/frontend/packages/kitconcept-intranet/src/config/slots.ts b/frontend/packages/kitconcept-intranet/src/config/slots.ts index 72f61ea6b..f25b7c4ec 100644 --- a/frontend/packages/kitconcept-intranet/src/config/slots.ts +++ b/frontend/packages/kitconcept-intranet/src/config/slots.ts @@ -1,5 +1,6 @@ import type { ConfigType } from '@plone/registry'; import { ContentTypeCondition } from '@plone/volto/helpers/Slots'; +import { getBaseUrl, isCmsUi } from '@plone/volto/helpers/Url/Url'; import IntranetCSSInjector from '../slots/IntranetCSSInjector/IntranetCSSInjector'; import DocumentByLine from '../slots/DocumentByLine/DocumentByLine'; import AboutThisContent from '../slots/AboutThisContent/AboutThisContent'; @@ -9,6 +10,7 @@ import StickyFeedbackButton from '../components/StickyFeedbackButton/StickyFeedb import ListingDisclaimer from '../slots/ListingDisclaimer/ListingDisclaimer'; import NavigationTreePortal from '../components/NavigationTree/NavigationTreePortal'; import HideFooter from '../slots/HideFooter/HideFooter'; +import CommentsSlot from '../slots/Comments/CommentsSlot'; export default function install(config: ConfigType) { config.registerSlotComponent({ @@ -41,6 +43,23 @@ export default function install(config: ConfigType) { ]), ], }); + config.registerSlotComponent({ + slot: 'preFooter', + name: 'Comments', + component: CommentsSlot, + predicates: [ + ({ content, location }) => { + const pathname = location.pathname; + const contentPath = pathname === '/' ? '' : pathname; + + return ( + Boolean(content?.allow_discussion) && + !isCmsUi(pathname) && + getBaseUrl(pathname) === contentPath + ); + }, + ], + }); config.registerSlotComponent({ slot: 'belowContent', name: 'Content Interactions', diff --git a/frontend/packages/kitconcept-intranet/src/customizations/volto/components/theme/Comments/Comments.jsx b/frontend/packages/kitconcept-intranet/src/customizations/volto/components/theme/Comments/Comments.jsx new file mode 100644 index 000000000..c620060fd --- /dev/null +++ b/frontend/packages/kitconcept-intranet/src/customizations/volto/components/theme/Comments/Comments.jsx @@ -0,0 +1,340 @@ +/** + * OVERRIDE Comments.jsx + * REASON: Update the comments component layout, styling, and footer placement. + * FILE: https://github.com/plone/volto/blob/main/packages/volto/src/components/theme/Comments/Comments.jsx + * FILE VERSION: Volto 19.3.0 + * TICKET: https://gitlab.kitconcept.io/kitconcept/distribution-kitconcept-intranet/-/work_items/557 + * DATE: 2026-08-06 + * DEVELOPER: @iRohitSingh + */ + +import { useCallback, useEffect, useMemo, useState } from 'react'; +import PropTypes from 'prop-types'; +import { createPortal } from 'react-dom'; +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; +import { useDispatch, useSelector, shallowEqual } from 'react-redux'; +import { compose } from 'redux'; +import { Button, Container } from '@plone/components'; + +import { + addComment, + deleteComment, + listComments, + listMoreComments, +} from '@plone/volto/actions/comments/comments'; +import { CommentEditModal } from '@plone/volto/components/theme/Comments'; +import Icon from '@plone/volto/components/theme/Icon/Icon'; +import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable'; +import { flattenToAppURL, getBaseUrl } from '@plone/volto/helpers/Url/Url'; +import { usePrevious } from '@plone/volto/helpers/Utils/usePrevious'; +import useUser from '@plone/volto/hooks/user/useUser'; +import commentSVG from '@plone/volto/icons/comment.svg'; +import sendSVG from '@plone/volto/icons/send.svg'; +import PersonPill from '@kitconcept/intranet/components/PersonPill/PersonPill'; + +const messages = defineMessages({ + addComment: { + id: 'Add comment... (@ mention a person)', + defaultMessage: 'Add comment... (@ mention a person)', + }, + comments: { + id: 'Comments', + defaultMessage: 'Comments', + }, + delete: { + id: 'Delete', + defaultMessage: 'Delete', + }, + edit: { + id: 'Edit', + defaultMessage: 'Edit', + }, + reply: { + id: 'Reply', + defaultMessage: 'Reply', + }, + send: { + id: 'Send comment', + defaultMessage: 'Send comment', + }, + visibility: { + id: 'Visible to everyone who can see this page.', + defaultMessage: 'Visible to everyone who can see this page.', + }, +}); + +const useComments = () => { + const items = useSelector((state) => state.comments.items, shallowEqual); + const next = useSelector((state) => state.comments.next, shallowEqual); + const itemsTotal = useSelector( + (state) => state.comments.items_total, + shallowEqual, + ); + const permissions = useSelector( + (state) => state.comments.permissions || {}, + shallowEqual, + ); + const addRequest = useSelector((state) => state.comments.add, shallowEqual); + const deleteRequest = useSelector( + (state) => state.comments.delete, + shallowEqual, + ); + return { items, next, itemsTotal, permissions, addRequest, deleteRequest }; +}; + +const CommentComposer = ({ onSubmit, user, compact = false }) => { + const intl = useIntl(); + const [value, setValue] = useState(''); + const submit = (event) => { + event.preventDefault(); + const comment = value.trim(); + if (!comment) return; + onSubmit(comment); + setValue(''); + }; + + return ( +
+ ); +}; + +CommentComposer.propTypes = { + compact: PropTypes.bool, + onSubmit: PropTypes.func.isRequired, + user: PropTypes.object, +}; + +const CommentsView = ({ pathname, moment }) => { + const intl = useIntl(); + const dispatch = useDispatch(); + const user = useUser(); + const [showEdit, setShowEdit] = useState(false); + const [editId, setEditId] = useState(null); + const [editText, setEditText] = useState(null); + const [replyTo, setReplyTo] = useState(null); + const { items, next, itemsTotal, permissions, addRequest, deleteRequest } = + useComments(); + const previousPathname = usePrevious(pathname); + const previousAddLoading = usePrevious(addRequest.loading); + const previousDeleteLoading = usePrevious(deleteRequest.loading); + + useEffect(() => { + if ( + pathname !== previousPathname || + (previousAddLoading && addRequest.loaded) || + (previousDeleteLoading && deleteRequest.loaded) + ) { + dispatch(listComments(getBaseUrl(pathname))); + } + }, [ + addRequest.loaded, + deleteRequest.loaded, + dispatch, + pathname, + previousAddLoading, + previousDeleteLoading, + previousPathname, + ]); + + const submitComment = (text, parentId = null) => { + dispatch(addComment(getBaseUrl(pathname), text, parentId)); + setReplyTo(null); + }; + + const onEdit = useCallback((value) => { + setShowEdit(true); + setEditText(value.text); + setEditId(value.id); + }, []); + + const closeEdit = useCallback(() => { + setShowEdit(false); + setEditId(null); + setEditText(null); + setReplyTo(null); + }, []); + + const commentsById = useMemo(() => { + const result = items.reduce( + (comments, item) => ({ + ...comments, + [item.comment_id]: { comment: item, children: [] }, + }), + {}, + ); + items.forEach((item) => { + if (item.in_reply_to && result[item.in_reply_to]) { + result[item.in_reply_to].children.push(item); + } + }); + return result; + }, [items]); + + const primaryComments = items.filter((item) => !item.in_reply_to); + const relativeDate = moment.default; + + const renderComment = (comment) => { + const children = commentsById[comment.comment_id]?.children || []; + return ( +