feat: update ui
This commit is contained in:
+17
-12
@@ -41,6 +41,7 @@ export default function ChatsSection({ selected, onSelect }: Props) {
|
||||
|
||||
return items.slice(0, 100).map((i) => ({
|
||||
...i,
|
||||
contact: i.accountLid ? contacts.findById(i.accountLid) : null,
|
||||
from: i.isGroup
|
||||
? contacts.findById(i.previewMessage?.author || null)
|
||||
: null,
|
||||
@@ -81,34 +82,37 @@ export default function ChatsSection({ selected, onSelect }: Props) {
|
||||
{chats == null || isLoading
|
||||
? [...Array(20)].map((_, i) => (
|
||||
<div key={i} className="w-full flex items-center gap-3 px-3 mb-4">
|
||||
<Skeleton key={i} className="size-12 rounded-full bg-accent" />
|
||||
<Skeleton className="size-12 rounded-full bg-accent" />
|
||||
<div className="flex-1">
|
||||
<Skeleton
|
||||
key={i}
|
||||
className="flex-1 h-4 bg-accent mb-2 w-1/2"
|
||||
/>
|
||||
<Skeleton key={i} className="flex-1 h-11 bg-accent" />
|
||||
<Skeleton className="flex-1 h-4 bg-accent mb-2 w-1/2" />
|
||||
<Skeleton className="flex-1 h-11 bg-accent" />
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
: null}
|
||||
|
||||
{filteredChats?.map((chat) => (
|
||||
{filteredChats?.map((chat) => {
|
||||
const title =
|
||||
chat.contact?.formattedName ||
|
||||
chat.contact?.name ||
|
||||
chat.formattedTitle ||
|
||||
chat.name ||
|
||||
"No title";
|
||||
|
||||
return (
|
||||
<button
|
||||
key={chat.id}
|
||||
onClick={() => onSelect(chat.id)}
|
||||
className={`flex w-full items-center gap-3 rounded-xl px-3 py-3 text-left transition cursor-pointer ${selected === chat.id ? "bg-accent" : "hover:bg-muted/70"}`}
|
||||
>
|
||||
<Avatar
|
||||
name={chat.formattedTitle || chat.name}
|
||||
name={title}
|
||||
icon={chat.isGroup ? <UsersIcon size={16} /> : null}
|
||||
/>
|
||||
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<p className="truncate text-sm font-semibold">
|
||||
{chat.formattedTitle || chat.name}
|
||||
</p>
|
||||
<p className="truncate text-sm font-semibold">{title}</p>
|
||||
<span className="shrink-0 text-[11px] text-muted-foreground">
|
||||
{dayjs((chat.timestamp || 0) * 1000).fromNow()}
|
||||
</span>
|
||||
@@ -128,7 +132,8 @@ export default function ChatsSection({ selected, onSelect }: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
+28
-5
@@ -12,7 +12,7 @@ import {
|
||||
SendIcon,
|
||||
XIcon,
|
||||
} from "lucide-react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import dayjs from "dayjs";
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
import MessageMedia from "@/components/message-media";
|
||||
@@ -187,9 +187,18 @@ export default function MessagesSection({ chatId, maxCount = 50 }: Props) {
|
||||
className={`mb-3 flex ${item.fromMe ? "justify-end" : "justify-start"}`}
|
||||
>
|
||||
<div className="max-w-[82%] sm:max-w-[65%]">
|
||||
<p className="mb-1 text-xs text-muted-foreground">
|
||||
<a
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
router.push(
|
||||
`/?chatId=${getId(item.author || item.from?.id)}`,
|
||||
);
|
||||
}}
|
||||
className="mb-1 text-xs text-muted-foreground"
|
||||
>
|
||||
{getFormattedName(item.from) || item.notifyName}
|
||||
</p>
|
||||
</a>
|
||||
<div
|
||||
className={`rounded-2xl px-4 py-2.5 text-sm shadow-sm ${item.fromMe ? "rounded-br-md bg-[#d8f5e8] dark:bg-[#26855c] text-foreground" : "rounded-bl-md bg-card text-card-foreground"}`}
|
||||
>
|
||||
@@ -290,9 +299,8 @@ export default function MessagesSection({ chatId, maxCount = 50 }: Props) {
|
||||
i % 2 === 0 ? "self-start" : "self-end",
|
||||
)}
|
||||
>
|
||||
<Skeleton key={i} className="w-20 mb-3 h-6 bg-card" />
|
||||
<Skeleton className="w-20 mb-3 h-6 bg-card" />
|
||||
<Skeleton
|
||||
key={i}
|
||||
className={cn(
|
||||
"w-full h-20 bg-card rounded-2xl",
|
||||
["h-20", "h-32", "h-24", "h-40"][i % 4],
|
||||
@@ -332,6 +340,7 @@ function MessageInputSection({
|
||||
chatId?: string | null;
|
||||
refetch: () => void;
|
||||
}) {
|
||||
const fileRef = useRef<HTMLInputElement>(null);
|
||||
const { client, isReady } = useWAClient();
|
||||
const [message, setMessage] = useState("");
|
||||
const [files, setFiles] = useState<{ id: string; file: File }[]>([]);
|
||||
@@ -414,6 +423,19 @@ function MessageInputSection({
|
||||
|
||||
return (
|
||||
<div className="border-t border-border bg-card px-3 py-3 sm:py-4">
|
||||
<input
|
||||
type="file"
|
||||
ref={fileRef}
|
||||
multiple
|
||||
className="hidden"
|
||||
onChange={(e) => {
|
||||
if (e.target.files?.length) {
|
||||
onFileAttached([...e.target.files]);
|
||||
}
|
||||
e.target.value = "";
|
||||
}}
|
||||
/>
|
||||
|
||||
{files.length > 0 && (
|
||||
<div className="flex items-center gap-2 mb-3 overflow-x-auto">
|
||||
{files.map((i) => (
|
||||
@@ -429,6 +451,7 @@ function MessageInputSection({
|
||||
<button
|
||||
aria-label="Add attachment"
|
||||
className="grid size-10 shrink-0 place-items-center rounded-full text-muted-foreground hover:bg-muted hover:text-muted-foreground"
|
||||
onClick={() => fileRef.current?.click()}
|
||||
>
|
||||
<PaperclipIcon size={19} />
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user