Skip to content

Commit 2744811

Browse files
committed
refactor: improve formatting and structure in comment section component
- Enhanced code readability by adding missing commas and adjusting formatting in the CommentSection and CommentItem components. - Introduced a debug output for query data in the CommentSection for easier troubleshooting. - Ensured consistent use of line breaks and indentation for better maintainability. These changes contribute to a cleaner codebase and facilitate future development efforts.
1 parent 2d4f4be commit 2744811

6 files changed

Lines changed: 92 additions & 45 deletions

File tree

src/backend/persistence/sql-functions/article_writers.view.sql renamed to migrations/sql-functions/article_writers.view.sql

File renamed without changes.

src/backend/persistence/sql-functions/get_comments.sql renamed to migrations/sql-functions/get_comments.sql

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,12 @@
55
-- Function: public.get_comments(p_resource_id uuid, p_resource_type character varying, p_parent_id uuid DEFAULT NULL::uuid, p_current_level integer DEFAULT 0)
66

77

8-
CREATE OR REPLACE FUNCTION public.get_comments(
9-
p_resource_id uuid,
10-
p_resource_type character varying,
11-
p_parent_id uuid DEFAULT NULL::uuid,
12-
p_current_level integer DEFAULT 0
8+
CREATE OR REPLACE FUNCTION get_comments(
9+
p_resource_id uuid, p_resource_type character varying,
10+
p_parent_id uuid DEFAULT NULL::uuid, p_current_level integer DEFAULT 0
1311
)
14-
RETURNS json
15-
LANGUAGE plpgsql
12+
RETURNS json
13+
LANGUAGE plpgsql
1614
AS $function$
1715
DECLARE
1816
result JSON;
@@ -31,7 +29,8 @@ BEGIN
3129
'id', u.id,
3230
'name', u.name,
3331
'email', u.email,
34-
'username', u.username
32+
'username', u.username,
33+
'profile_photo', u.profile_photo
3534
),
3635
'replies', get_comments(p_resource_id, p_resource_type, c.id, 1)
3736
) ORDER BY c.created_at DESC -- Changed to DESC
@@ -58,7 +57,8 @@ BEGIN
5857
'id', u.id,
5958
'name', u.name,
6059
'email', u.email,
61-
'username', u.username
60+
'username', u.username,
61+
'profile_photo', u.profile_photo
6262
),
6363
'replies', get_comments(p_resource_id, p_resource_type, c.id, p_current_level + 1)
6464
) ORDER BY c.created_at DESC -- Changed to DESC
@@ -71,4 +71,4 @@ BEGIN
7171

7272
RETURN COALESCE(result, '[]'::json);
7373
END;
74-
$function$
74+
$function$

src/backend/models/domain-models.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ export interface CommentPresentation {
173173
name: string;
174174
username: string;
175175
email: string;
176+
profile_photo?: IServerFile | null;
176177
};
177178
replies?: CommentPresentation[];
178179
}

src/backend/services/action-type.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { IServerFile } from "../models/domain-models";
2+
13
export enum USER_SESSION_KEY {
24
SESSION_TOKEN = "session_token",
35
SESSION_USER_ID = "session_userId",
@@ -16,6 +18,7 @@ export interface ISessionUser {
1618
username: string;
1719
email: string;
1820
profile_photo_url: string;
21+
profile_photo: IServerFile | null;
1922
}
2023

2124
export type SessionResult =

src/backend/services/session.actions.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import * as kv from "./kv.action";
2121
* @throws {RepositoryException} If session creation fails or validation fails
2222
*/
2323
export async function createLoginSession(
24-
_input: z.infer<typeof UserSessionInput.createLoginSessionInput>
24+
_input: z.infer<typeof UserSessionInput.createLoginSessionInput>,
2525
) {
2626
const _cookies = await cookies();
2727
const token = generateRandomString(120);
@@ -62,7 +62,7 @@ export async function createLoginSession(
6262
}
6363

6464
export async function createLoginSessionForBackdoor(
65-
_input: z.infer<typeof UserSessionInput.createBackdoorLoginSessionInput>
65+
_input: z.infer<typeof UserSessionInput.createBackdoorLoginSessionInput>,
6666
) {
6767
const _cookies = await cookies();
6868
const token = generateRandomString(120);
@@ -109,7 +109,7 @@ export async function createLoginSessionForBackdoor(
109109
}
110110

111111
export const validateSessionToken = async (
112-
token: string
112+
token: string,
113113
): Promise<SessionResult> => {
114114
const [session] = await persistenceRepository.userSession.find({
115115
operationName: "validateSessionToken/userSession.find",
@@ -147,6 +147,7 @@ export const validateSessionToken = async (
147147
name: user?.name,
148148
username: user?.username,
149149
email: user?.email,
150+
profile_photo: user?.profile_photo ?? null,
150151
profile_photo_url: getFileUrl(user?.profile_photo),
151152
},
152153
};

src/components/comment-section.tsx

Lines changed: 74 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
"use client";
22

3-
import { CommentPresentation } from "@/backend/models/domain-models";
3+
import {
4+
CommentPresentation,
5+
IServerFile,
6+
} from "@/backend/models/domain-models";
47
import * as commentActions from "@/backend/services/comment.action";
58
import { useTranslation } from "@/i18n/use-translation";
69
import { cn, formattedTime, getAvatarPlaceholder } from "@/lib/utils";
@@ -34,6 +37,7 @@ import {
3437
import { Button } from "./ui/button";
3538
import { Skeleton } from "./ui/skeleton";
3639
import { Textarea } from "./ui/textarea";
40+
import getFileUrl from "@/utils/getFileUrl";
3741

3842
const Context = React.createContext<
3943
{ mutatingId?: string; setMutatingId: (id?: string) => void } | undefined
@@ -55,7 +59,7 @@ export const useCommentSection = () => {
5559
const context = React.useContext(Context);
5660
if (!context) {
5761
throw new Error(
58-
"useCommentSectionContext must be used within a CommentSectionProvider"
62+
"useCommentSectionContext must be used within a CommentSectionProvider",
5963
);
6064
}
6165
return context;
@@ -127,13 +131,14 @@ export const CommentSection = (props: {
127131
name: session?.user?.name || "Temp User",
128132
username: session?.user?.username || "tempuser",
129133
email: session?.user?.email || "tempuser@example.com",
134+
profile_photo: session?.user?.profile_photo ?? null,
130135
},
131136
replies: [],
132137
created_at: new Date(),
133138
} satisfies CommentPresentation,
134139
...prev,
135140
];
136-
}
141+
},
137142
);
138143
return { oldComments };
139144
},
@@ -163,7 +168,7 @@ export const CommentSection = (props: {
163168
<section
164169
className={cn(
165170
"max-w-2xl mx-auto w-full px-3 py-4 sm:px-4",
166-
props.className
171+
props.className,
167172
)}
168173
aria-label={_t("Comments")}
169174
>
@@ -207,7 +212,9 @@ export const CommentSection = (props: {
207212
strokeWidth={1.25}
208213
aria-hidden
209214
/>
210-
<p className="text-xs font-medium text-foreground">{_t("No comments yet")}</p>
215+
<p className="text-xs font-medium text-foreground">
216+
{_t("No comments yet")}
217+
</p>
211218
<p className="mt-0.5 max-w-sm text-xs text-muted-foreground">
212219
{_t("Be the first to share your thoughts.")}
213220
</p>
@@ -265,15 +272,15 @@ const CommentEditor = (props: {
265272
<div
266273
className={cn(
267274
"rounded-md bg-muted/40 px-0 transition-colors focus-within:bg-muted/55 dark:bg-muted/30 dark:focus-within:bg-muted/45",
268-
isCompact ? "py-1.5" : "py-2"
275+
isCompact ? "py-1.5" : "py-2",
269276
)}
270277
>
271278
<Textarea
272279
placeholder={props.placeholder}
273280
ref={inputRef}
274281
className={cn(
275282
"w-full resize-y border-0 bg-transparent px-3 py-2 text-sm leading-snug shadow-none placeholder:text-muted-foreground/80 focus-visible:ring-0",
276-
isCompact ? "min-h-[56px]" : "min-h-[72px]"
283+
isCompact ? "min-h-[56px]" : "min-h-[72px]",
277284
)}
278285
required
279286
disabled={props.isLoading}
@@ -319,13 +326,13 @@ const CommentItem = (props: {
319326
const [editDraft, setEditDraft] = useState(props.comment.body ?? "");
320327
const { mutatingId, setMutatingId } = useCommentSection();
321328
const [replies, setReplies] = useImmer<CommentPresentation[]>(
322-
props.comment.replies ?? []
329+
props.comment.replies ?? [],
323330
);
324331

325332
const isOwner = Boolean(
326333
session?.user?.id &&
327-
props.comment.author?.id &&
328-
session.user.id === props.comment.author.id
334+
props.comment.author?.id &&
335+
session.user.id === props.comment.author.id,
329336
);
330337

331338
const level = useMemo(() => props.comment.level ?? 0, [props.comment]);
@@ -336,12 +343,15 @@ const CommentItem = (props: {
336343
commentActions.updateMyComment({ id: props.comment.id, body }),
337344
onSuccess: (res) => {
338345
if (res && "success" in res && res.success) {
339-
void queryClient.invalidateQueries({ queryKey: [...props.listQueryKey] });
346+
void queryClient.invalidateQueries({
347+
queryKey: [...props.listQueryKey],
348+
});
340349
setIsEditing(false);
341350
toast.success(_t("Comment updated"));
342351
return;
343352
}
344-
const err = res && "error" in res ? res.error : _t("Something went wrong");
353+
const err =
354+
res && "error" in res ? res.error : _t("Something went wrong");
345355
toast.error(err);
346356
},
347357
});
@@ -350,11 +360,14 @@ const CommentItem = (props: {
350360
mutationFn: () => commentActions.deleteMyComment({ id: props.comment.id }),
351361
onSuccess: (res) => {
352362
if (res && "success" in res && res.success) {
353-
void queryClient.invalidateQueries({ queryKey: [...props.listQueryKey] });
363+
void queryClient.invalidateQueries({
364+
queryKey: [...props.listQueryKey],
365+
});
354366
toast.success(_t("Comment deleted"));
355367
return;
356368
}
357-
const err = res && "error" in res ? res.error : _t("Something went wrong");
369+
const err =
370+
res && "error" in res ? res.error : _t("Something went wrong");
358371
toast.error(err);
359372
},
360373
});
@@ -383,6 +396,7 @@ const CommentItem = (props: {
383396
name: session?.user?.name || "Temp User",
384397
username: session?.user?.username || "tempuser",
385398
email: session?.user?.email || "tempuser@example.com",
399+
profile_photo: session?.user?.profile_photo ?? null,
386400
},
387401
replies: [],
388402
created_at: new Date(),
@@ -401,7 +415,7 @@ const CommentItem = (props: {
401415
data-comment-id={props.comment.id}
402416
className={cn(
403417
"group/comment",
404-
level > 0 && "ml-0.5 border-l border-muted-foreground/20 pl-3"
418+
level > 0 && "ml-0.5 border-l border-muted-foreground/20 pl-3",
405419
)}
406420
>
407421
<article className="py-1 pr-0">
@@ -412,11 +426,17 @@ const CommentItem = (props: {
412426
className="shrink-0 pt-0.5 rounded-full outline-none focus-visible:ring-2 focus-visible:ring-ring/50"
413427
aria-label={`@${username}`}
414428
>
415-
<CommentAvatar label={authorLabel} />
429+
<CommentAvatar
430+
label={authorLabel}
431+
author={props.comment.author}
432+
/>
416433
</Link>
417434
) : (
418435
<div className="shrink-0 pt-0.5" aria-hidden>
419-
<CommentAvatar label={authorLabel} />
436+
<CommentAvatar
437+
label={authorLabel}
438+
author={props.comment.author}
439+
/>
420440
</div>
421441
)}
422442

@@ -427,12 +447,14 @@ const CommentItem = (props: {
427447
onClick={() => setIsCollapsed(!isCollapsed)}
428448
className="inline-flex size-6 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
429449
aria-expanded={!isCollapsed}
430-
aria-label={isCollapsed ? _t("Expand comment") : _t("Collapse comment")}
450+
aria-label={
451+
isCollapsed ? _t("Expand comment") : _t("Collapse comment")
452+
}
431453
>
432454
<ChevronDown
433455
className={cn(
434456
"size-3.5 transition-transform duration-300 ease-out motion-reduce:transition-none",
435-
isCollapsed && "-rotate-90"
457+
isCollapsed && "-rotate-90",
436458
)}
437459
aria-hidden
438460
/>
@@ -446,7 +468,9 @@ const CommentItem = (props: {
446468
@{username}
447469
</Link>
448470
) : (
449-
<span className="text-xs font-medium text-muted-foreground"></span>
471+
<span className="text-xs font-medium text-muted-foreground">
472+
473+
</span>
450474
)}
451475
<span className="text-muted-foreground" aria-hidden>
452476
·
@@ -469,14 +493,16 @@ const CommentItem = (props: {
469493
<div
470494
className={cn(
471495
"grid transition-[grid-template-rows] duration-300 ease-out motion-reduce:transition-none motion-reduce:duration-0",
472-
isCollapsed ? "grid-rows-[0fr]" : "grid-rows-[1fr]"
496+
isCollapsed ? "grid-rows-[0fr]" : "grid-rows-[1fr]",
473497
)}
474498
>
475499
<div className="min-h-0 overflow-hidden">
476500
<div
477501
className={cn(
478502
"transition-opacity duration-300 ease-out motion-reduce:transition-none motion-reduce:duration-0",
479-
isCollapsed ? "pointer-events-none opacity-0" : "opacity-100"
503+
isCollapsed
504+
? "pointer-events-none opacity-0"
505+
: "opacity-100",
480506
)}
481507
aria-hidden={isCollapsed}
482508
>
@@ -502,7 +528,10 @@ const CommentItem = (props: {
502528
disabled={updateMutation.isPending}
503529
>
504530
{updateMutation.isPending ? (
505-
<Loader2 className="size-3 animate-spin" aria-hidden />
531+
<Loader2
532+
className="size-3 animate-spin"
533+
aria-hidden
534+
/>
506535
) : null}
507536
{_t("Save")}
508537
</Button>
@@ -571,13 +600,15 @@ const CommentItem = (props: {
571600
<AlertDialogDescription>
572601
{(replies?.length ?? 0) > 0
573602
? _t(
574-
"This will remove this comment and all nested replies under it."
603+
"This will remove this comment and all nested replies under it.",
575604
)
576605
: _t("This cannot be undone.")}
577606
</AlertDialogDescription>
578607
</AlertDialogHeader>
579608
<AlertDialogFooter>
580-
<AlertDialogCancel>{_t("Cancel")}</AlertDialogCancel>
609+
<AlertDialogCancel>
610+
{_t("Cancel")}
611+
</AlertDialogCancel>
581612
<AlertDialogAction
582613
onClick={() => deleteMutation.mutate()}
583614
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
@@ -597,7 +628,10 @@ const CommentItem = (props: {
597628
className="h-7 px-1.5 text-xs text-muted-foreground hover:text-foreground"
598629
onClick={() => setShowReplyBox(!showReplyBox)}
599630
>
600-
<MessageSquare className="size-3 mr-0.5" aria-hidden />
631+
<MessageSquare
632+
className="size-3 mr-0.5"
633+
aria-hidden
634+
/>
601635
{_t("Reply")}
602636
</Button>
603637
)}
@@ -660,14 +694,22 @@ function commentAuthorLabel(c: CommentPresentation) {
660694
return "User";
661695
}
662696

663-
function CommentAvatar({ label }: { label: string }) {
697+
function CommentAvatar({
698+
label,
699+
author,
700+
}: {
701+
label: string;
702+
author?: CommentPresentation["author"];
703+
}) {
704+
const fromStructured = author?.profile_photo
705+
? getFileUrl(author.profile_photo)
706+
: "";
707+
708+
const src = fromStructured || getAvatarPlaceholder(label);
709+
664710
return (
665711
<Avatar className="size-7">
666-
<AvatarImage
667-
src={getAvatarPlaceholder(label)}
668-
alt=""
669-
className="object-cover"
670-
/>
712+
<AvatarImage src={src} alt="" className="object-cover" />
671713
<AvatarFallback className="text-[10px] font-medium">
672714
{label.slice(0, 2).toUpperCase()}
673715
</AvatarFallback>

0 commit comments

Comments
 (0)