Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/app/[lang]/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ html {
--comments-menu-item-font-weight: var(--font-weight-regular);
--comments-menu-item-danger-font-weight: var(--font-weight-semi-bold);

/* user tags */
--tag-text-stroke: 0.5px var(--color-midnight);

/* icon */
--icon-color: var(--color-papaya);
--icon-size-24: 24px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { DotsThreeOutline } from "@phosphor-icons/react";
import { useTranslation } from "react-i18next";
import { CommentActionMenu } from "./CommentActionMenu";
import { CommentText, MenuAction } from "./styles";
import { useCommentTag } from "./hooks/useCommentTag";

type MenuState = {
isOpen: boolean;
Expand All @@ -21,10 +22,11 @@ type Props = {

export function CommentDisplay({ commentId, content, menu }: Props) {
const { t } = useTranslation();
const { renderHighlightedText } = useCommentTag();

return (
<>
<CommentText>{content}</CommentText>
<CommentText>{renderHighlightedText(content)}</CommentText>
<MenuAction
ref={menu.buttonRef}
onClick={menu.onToggle}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import { useCreateComment } from "@/hooks/useCreateComment";
import { useDeleteComment } from "@/hooks/useDeleteComment";
import { useUpdateComment } from "@/hooks/useUpdateComment";
import { Id, TimedText } from "need4deed-sdk";
import { useState } from "react";
import { useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { Comment } from "./Comment";
import { DeleteCommentDialog } from "./DeleteCommentDialog";
import { useCommentDelete } from "./hooks/useCommentDelete";
import { useCommentEdit } from "./hooks/useCommentEdit";
import { useCommentMenu } from "./hooks/useCommentMenu";
import { AddCommentButton, Container, NewCommentSection, TextArea } from "./styles";
import { AddCommentButton, Container, NewCommentSection, TagOverlay, TextArea } from "./styles";
import { useCommentTag } from "./hooks/useCommentTag";

type Props = {
entityId: Id;
Expand All @@ -24,10 +25,13 @@ export function EntityComments({ entityId, entityType, comments, testId }: Props
const { t } = useTranslation();
const { mutate: createComment, isPending: isCreating } = useCreateComment(entityId, entityType);
const [newCommentText, setNewCommentText] = useState("");
const textAreaRef = useRef<HTMLTextAreaElement>(null);
const overlayRef = useRef<HTMLDivElement>(null);

const edit = useCommentEdit();
const deleteState = useCommentDelete();
const menu = useCommentMenu();
const { renderHighlightedText } = useCommentTag();

const { mutate: updateComment, isPending: isUpdating } = useUpdateComment(
entityId,
Expand Down Expand Up @@ -61,6 +65,11 @@ export function EntityComments({ entityId, entityType, comments, testId }: Props
}
};

const handleScroll = () => {
if (!textAreaRef?.current || !overlayRef?.current) return;
overlayRef.current.style.transform = `translateY(-${textAreaRef.current.scrollTop}px)`;
};

const handleSaveEdit = () => {
if (!edit.editText.trim() || !edit.editingCommentId) return;

Expand Down Expand Up @@ -124,22 +133,24 @@ export function EntityComments({ entityId, entityType, comments, testId }: Props
))}

<NewCommentSection>
<TagOverlay ref={overlayRef}>{renderHighlightedText(newCommentText)}</TagOverlay>
<TextArea
ref={textAreaRef}
placeholder={t("dashboard.commentsSection.placeholder")}
value={newCommentText}
onChange={(e) => setNewCommentText(e.target.value)}
onKeyPress={handleKeyPress}
data-testid="comment-textarea"
onScroll={handleScroll}
/>
<AddCommentButton
onClick={handleAddComment}
disabled={!newCommentText.trim() || isCreating}
data-testid="add-comment-button"
>
{t("dashboard.commentsSection.addComment")}
</AddCommentButton>
</NewCommentSection>

<AddCommentButton
onClick={handleAddComment}
disabled={!newCommentText.trim() || isCreating}
data-testid="add-comment-button"
>
{t("dashboard.commentsSection.addComment")}
</AddCommentButton>
<DeleteCommentDialog
isOpen={deleteState.deleteDialogOpen}
authorName={deleteState.deleteAuthorName}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Link from "next/link";

export function useCommentTag() {
const renderHighlightedText = (value: string) => {
const parts = value.split(/((?<=^|\s)@\w+)/g);
return parts.map((value, idx) => {
if (value.startsWith("@")) {
// TODO run logic here to find userId for url
// TODO add condition, if user valid pass return Link, else fail return value
return (
// TODO add userId to path
<Link href={`/volunteers/:userId`} key={`${value}${idx}`} className="tag">
{value}
</Link>
);
} else {
return value;
}
});
};

return { renderHighlightedText };
}
88 changes: 68 additions & 20 deletions src/components/Dashboard/Profile/sections/Comments/common/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ export const CommentText = styled.div`
color: var(--color-midnight);
align-self: stretch;
white-space: pre-wrap;

.tag {
color: var(--color-midnight);
font-weight: bold;
text-decoration: none;
border-radius: var(--border-radius-xs);
&:hover {
opacity: 0.8;
}
}
`;

export const MenuAction = styled.button`
Expand All @@ -84,54 +94,58 @@ export const MenuAction = styled.button`
`;

export const NewCommentSection = styled.div`
position: relative;
display: flex;
flex-direction: column;
align-items: flex-end;
padding: 0;
gap: var(--spacing-16);
width: 100%;
height: 112px;
overflow-y: hidden;
align-self: stretch;
border: var(--border-width-thin) solid var(--color-grey-200);
border-radius: var(--border-radius-small);
`;

export const TextArea = styled.textarea`
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: flex-start;
position: absolute;
padding: var(--spacing-16);
gap: var(--spacing-8);
margin: 0;
width: 100%;
min-height: 112px;
background: var(--color-white);
border: var(--border-width-thin) solid var(--color-grey-200);
border-radius: var(--border-radius-small);
font-style: normal;
font-weight: var(--font-weight-regular);
height: 100%;
top: 0;
left: 0;
background: transparent;
color: transparent;
caret-color: var(--color-midnight);
font-family: inherit;
font-size: var(--text-p-font-size);
line-height: var(--text-p-line-height);
letter-spacing: var(--letter-spacing-tight);
color: var(--color-midnight);
resize: vertical;
align-self: stretch;
white-space: pre-wrap;
word-wrap: break-word;
box-sizing: border-box;
z-index: 2;
resize: none;
overflow-y: scroll;
border: none;
scrollbar-gutter: stable;

&::placeholder {
color: var(--color-grey-500);
}

&:focus {
outline: none;
border-color: var(--color-midnight);
}
`;

export const AddCommentButton = styled.button`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
align-self: end;
padding: var(--spacing-16) var(--spacing-24);
gap: var(--spacing-8);
height: 56px;
aspect-ratio: 4/1;
background: var(--color-aubergine);
border-radius: var(--button-border-radius);
border: none;
Expand Down Expand Up @@ -225,3 +239,37 @@ export const EditSaveButton = styled.button`
background: var(--color-aubergine-light);
}
`;

export const TagOverlay = styled.div`
position: absolute;
top: 0;
left: 0;
width: 100%;
padding: var(--spacing-16);
margin: 0;
font-family: inherit;
font-size: var(--text-p-font-size);
line-height: var(--text-p-line-height);
letter-spacing: var(--letter-spacing-tight);
white-space: pre-wrap;
word-wrap: break-word;
box-sizing: border-box;
color: var(--color-midnight);
z-index: 1;
pointer-events: none;
user-selects: none;
font-style: normal;
font-weight: var(--font-weight-regular);
will-change: transform;
scrollbar-gutter: stable;
overflow-y: hidden;
.tag {
color: var(--color-midnight);
text-decoration: none;
padding: 0;
margin: 0;
border: none;
-webkit-text-stroke: var(--tag-text-stroke);
border-radius: var(--border-radius-xs);
}
`;
Loading