mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2025-08-01 06:33:52 +08:00
[offers][refactor] tweak comments list
This commit is contained in:
@ -110,10 +110,10 @@ export default function ProfileComments({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="bh-white h-fit px-4 lg:h-[calc(100vh-4.5rem)] lg:overflow-y-auto">
|
<div className="bh-white h-fit p-4 lg:h-[calc(100vh-4.5rem)] lg:overflow-y-auto">
|
||||||
<div className="bg-white pt-4 lg:sticky lg:top-0">
|
<div className="bg-white lg:sticky lg:top-0">
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<div className="grid w-fit grid-cols-1 space-y-2 md:grid-cols-2 md:grid-cols-2 md:space-y-0 md:space-x-4">
|
<div className="grid w-fit grid-cols-1 space-y-2 md:grid-cols-2 md:space-y-0 md:space-x-4">
|
||||||
<div className="col-span-1 flex justify-end">
|
<div className="col-span-1 flex justify-end">
|
||||||
{isEditable && (
|
{isEditable && (
|
||||||
<Tooltip tooltipContent="Copy this link to edit your profile later">
|
<Tooltip tooltipContent="Copy this link to edit your profile later">
|
||||||
@ -169,57 +169,62 @@ export default function ProfileComments({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 className="mt-2 mb-6 text-2xl font-bold">Discussions</h2>
|
<div className="mt-2 mb-6 bg-white">
|
||||||
{isEditable || session?.user?.name ? (
|
<h2 className="text-2xl font-bold">Discussions</h2>
|
||||||
<div>
|
{isEditable || session?.user?.name ? (
|
||||||
<TextArea
|
<div>
|
||||||
label={`Comment as ${
|
<TextArea
|
||||||
isEditable ? profileName : session?.user?.name ?? 'anonymous'
|
label={`Comment as ${
|
||||||
}`}
|
isEditable ? profileName : session?.user?.name ?? 'anonymous'
|
||||||
placeholder="Type your comment here"
|
}`}
|
||||||
value={currentReply}
|
placeholder="Type your comment here"
|
||||||
onChange={(value) => setCurrentReply(value)}
|
value={currentReply}
|
||||||
/>
|
onChange={(value) => setCurrentReply(value)}
|
||||||
<div className="mt-2 flex w-full justify-end">
|
/>
|
||||||
<div className="w-fit">
|
<div className="mt-2 flex w-full justify-end">
|
||||||
<Button
|
<div className="w-fit">
|
||||||
disabled={
|
<Button
|
||||||
commentsQuery.isLoading ||
|
disabled={
|
||||||
!currentReply.length ||
|
commentsQuery.isLoading ||
|
||||||
createCommentMutation.isLoading
|
!currentReply.length ||
|
||||||
}
|
createCommentMutation.isLoading
|
||||||
display="block"
|
}
|
||||||
isLabelHidden={false}
|
display="block"
|
||||||
isLoading={createCommentMutation.isLoading}
|
isLabelHidden={false}
|
||||||
label="Comment"
|
isLoading={createCommentMutation.isLoading}
|
||||||
size="sm"
|
label="Comment"
|
||||||
variant="primary"
|
size="sm"
|
||||||
onClick={() => handleComment(currentReply)}
|
variant="primary"
|
||||||
/>
|
onClick={() => handleComment(currentReply)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<HorizontalDivider />
|
||||||
</div>
|
</div>
|
||||||
<HorizontalDivider />
|
) : (
|
||||||
</div>
|
<Button
|
||||||
) : (
|
className="mb-5"
|
||||||
<Button
|
display="block"
|
||||||
className="mb-5"
|
href={loginPageHref()}
|
||||||
display="block"
|
label="Sign in to join discussion"
|
||||||
href={loginPageHref()}
|
variant="tertiary"
|
||||||
label="Sign in to join discussion"
|
/>
|
||||||
variant="tertiary"
|
)}
|
||||||
/>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="w-full">
|
|
||||||
{replies?.map((reply: Reply) => (
|
|
||||||
<ExpandableCommentCard
|
|
||||||
key={reply.id}
|
|
||||||
comment={reply}
|
|
||||||
profileId={profileId}
|
|
||||||
token={isEditable ? token : undefined}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
|
<section className="w-full">
|
||||||
|
<ul className="space-y-8" role="list">
|
||||||
|
{replies?.map((reply: Reply) => (
|
||||||
|
<li key={reply.id}>
|
||||||
|
<ExpandableCommentCard
|
||||||
|
comment={reply}
|
||||||
|
profileId={profileId}
|
||||||
|
token={isEditable ? token : undefined}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
import { signIn, useSession } from 'next-auth/react';
|
import { signIn, useSession } from 'next-auth/react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import {
|
import { Button, Dialog, TextArea, useToast } from '@tih/ui';
|
||||||
ChatBubbleBottomCenterIcon,
|
|
||||||
TrashIcon,
|
|
||||||
} from '@heroicons/react/24/outline';
|
|
||||||
import { Button, Dialog, HorizontalDivider, TextArea, useToast } from '@tih/ui';
|
|
||||||
|
|
||||||
import { timeSinceNow } from '~/utils/offers/time';
|
import { timeSinceNow } from '~/utils/offers/time';
|
||||||
|
import { trpc } from '~/utils/trpc';
|
||||||
import { trpc } from '../../../../utils/trpc';
|
|
||||||
|
|
||||||
import type { Reply } from '~/types/offers';
|
import type { Reply } from '~/types/offers';
|
||||||
|
|
||||||
@ -125,80 +120,97 @@ export default function CommentCard({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="flex space-x-3">
|
||||||
<div className="flex pl-2">
|
{/* <div className="flex-shrink-0">
|
||||||
<div className="flex w-full flex-col">
|
<img
|
||||||
<div className="flex flex-row font-bold">
|
alt=""
|
||||||
|
className="h-10 w-10 rounded-full"
|
||||||
|
src={`https://images.unsplash.com/photo-${comment.imageId}?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80`}
|
||||||
|
/>
|
||||||
|
</div> */}
|
||||||
|
<div>
|
||||||
|
<div className="text-sm">
|
||||||
|
<p className="font-medium text-slate-900">
|
||||||
{user?.name ?? 'unknown user'}
|
{user?.name ?? 'unknown user'}
|
||||||
</div>
|
</p>
|
||||||
<div className="mt-2 mb-2 flex flex-row ">{message}</div>
|
</div>
|
||||||
<div className="flex flex-row items-center justify-start space-x-4 ">
|
<div className="mt-1 text-sm text-slate-700">
|
||||||
<div className="flex flex-col text-sm font-light text-slate-400">{`${timeSinceNow(
|
<p className="break-all">{message}</p>
|
||||||
createdAt,
|
</div>
|
||||||
)} ago`}</div>
|
<div className="mt-2 space-x-2 text-sm">
|
||||||
{replyLength > 0 && (
|
<span className="font-medium text-slate-500">
|
||||||
<div
|
{timeSinceNow(createdAt)} ago
|
||||||
className="text-primary-600 flex cursor-pointer flex-col text-sm hover:underline"
|
</span>{' '}
|
||||||
|
<span className="font-medium text-slate-500">·</span>{' '}
|
||||||
|
{replyLength > 0 && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
className="font-medium text-slate-900"
|
||||||
|
type="button"
|
||||||
onClick={handleExpanded}>
|
onClick={handleExpanded}>
|
||||||
{isExpanded ? `Hide replies` : `View replies (${replyLength})`}
|
{isExpanded ? `Hide replies` : `View replies (${replyLength})`}
|
||||||
</div>
|
</button>
|
||||||
)}
|
<span className="font-medium text-slate-500">·</span>{' '}
|
||||||
{!disableReply && (
|
</>
|
||||||
<div className="flex flex-col">
|
)}
|
||||||
<Button
|
{!disableReply && (
|
||||||
icon={ChatBubbleBottomCenterIcon}
|
<>
|
||||||
isLabelHidden={true}
|
<button
|
||||||
label="Reply"
|
className="font-medium text-slate-900"
|
||||||
size="sm"
|
type="button"
|
||||||
variant="tertiary"
|
onClick={() => setIsReplying(!isReplying)}>
|
||||||
onClick={() => setIsReplying(!isReplying)}
|
Reply
|
||||||
/>
|
</button>
|
||||||
</div>
|
<span className="font-medium text-slate-500">·</span>{' '}
|
||||||
)}
|
</>
|
||||||
{deletable && (
|
)}
|
||||||
<>
|
{deletable && (
|
||||||
<Button
|
<>
|
||||||
disabled={deleteCommentMutation.isLoading}
|
<button
|
||||||
icon={TrashIcon}
|
className="font-medium text-slate-900"
|
||||||
isLabelHidden={true}
|
disabled={deleteCommentMutation.isLoading}
|
||||||
isLoading={deleteCommentMutation.isLoading}
|
type="button"
|
||||||
label="Delete"
|
onClick={() => setIsDialogOpen(true)}>
|
||||||
size="sm"
|
{deleteCommentMutation.isLoading ? 'Deleting...' : 'Delete'}
|
||||||
variant="tertiary"
|
</button>
|
||||||
onClick={() => setIsDialogOpen(true)}
|
{isDialogOpen && (
|
||||||
/>
|
<Dialog
|
||||||
{isDialogOpen && (
|
isShown={isDialogOpen}
|
||||||
<Dialog
|
primaryButton={
|
||||||
isShown={isDialogOpen}
|
<Button
|
||||||
primaryButton={
|
display="block"
|
||||||
<Button
|
label="Delete"
|
||||||
display="block"
|
variant="primary"
|
||||||
label="Delete"
|
onClick={() => {
|
||||||
variant="primary"
|
setIsDialogOpen(false);
|
||||||
onClick={() => {
|
handleDelete();
|
||||||
setIsDialogOpen(false);
|
}}
|
||||||
handleDelete();
|
/>
|
||||||
}}
|
}
|
||||||
/>
|
secondaryButton={
|
||||||
}
|
<Button
|
||||||
secondaryButton={
|
display="block"
|
||||||
<Button
|
label="Cancel"
|
||||||
display="block"
|
variant="tertiary"
|
||||||
label="Cancel"
|
onClick={() => setIsDialogOpen(false)}
|
||||||
variant="tertiary"
|
/>
|
||||||
onClick={() => setIsDialogOpen(false)}
|
}
|
||||||
/>
|
title="Are you sure you want to delete this comment?"
|
||||||
}
|
onClose={() => setIsDialogOpen(false)}>
|
||||||
title="Are you sure you want to delete this comment?"
|
<div>You cannot undo this operation.</div>
|
||||||
onClose={() => setIsDialogOpen(false)}>
|
</Dialog>
|
||||||
<div>You cannot undo this operation.</div>
|
)}
|
||||||
</Dialog>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</div>
|
||||||
)}
|
{!disableReply && isReplying && (
|
||||||
</div>
|
<div className="mt-2 mr-2">
|
||||||
{!disableReply && isReplying && (
|
<form
|
||||||
<div className="mt-2 mr-2">
|
onSubmit={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
handleReply();
|
||||||
|
}}>
|
||||||
<TextArea
|
<TextArea
|
||||||
isLabelHidden={true}
|
isLabelHidden={true}
|
||||||
label="Comment"
|
label="Comment"
|
||||||
@ -225,11 +237,10 @@ export default function CommentCard({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
)}
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
<HorizontalDivider />
|
</div>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -26,18 +26,22 @@ export default function ExpandableCommentCard({
|
|||||||
replyLength={comment.replies?.length ?? 0}
|
replyLength={comment.replies?.length ?? 0}
|
||||||
token={token}
|
token={token}
|
||||||
/>
|
/>
|
||||||
{comment.replies && (
|
{comment.replies && comment.replies.length > 0 && isExpanded && (
|
||||||
<div className="pl-8">
|
<div className="pt-4">
|
||||||
{isExpanded &&
|
<div className="border-l-4 border-slate-200 pl-4">
|
||||||
comment.replies.map((reply) => (
|
<ul className="space-y-4" role="list">
|
||||||
<CommentCard
|
{comment.replies.map((reply) => (
|
||||||
key={reply.id}
|
<li key={reply.id}>
|
||||||
comment={reply}
|
<CommentCard
|
||||||
disableReply={true}
|
comment={reply}
|
||||||
profileId={profileId}
|
disableReply={true}
|
||||||
token={token}
|
profileId={profileId}
|
||||||
/>
|
token={token}
|
||||||
))}
|
/>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user