Added enter animation, added loading and error state to conversations and communities, updated other small stuff

This commit is contained in:
Alois 2026-03-29 11:31:44 +02:00
commit ed53c17597
10 changed files with 116 additions and 53 deletions

View file

@ -8,8 +8,8 @@ import type {
} from "@tensamin/shared/features/conversation/schema";
interface contextValue {
conversations: Conversation[];
communities: Community[];
conversations: Conversation[] | null;
communities: Community[] | null;
}
const ConversationContext = React.createContext<contextValue | undefined>(
@ -24,8 +24,12 @@ const ConversationContext = React.createContext<contextValue | undefined>(
export default function ConversationProvider(props: {
children: React.ReactNode;
}) {
const [conversations, setConversations] = React.useState<Conversation[]>([]);
const [communities, setCommunities] = React.useState<Community[]>([]);
const [conversations, setConversations] = React.useState<
Conversation[] | null
>(null);
const [communities, setCommunities] = React.useState<Community[] | null>(
null,
);
const { send } = useSocket();
@ -39,6 +43,12 @@ export default function ConversationProvider(props: {
}
})
.catch(() => {
setConversations([
{
last_message_at: 0,
user_id: 0,
},
]);
toast("error", "Failed to load conversations");
});
@ -49,6 +59,13 @@ export default function ConversationProvider(props: {
}
})
.catch(() => {
setCommunities([
{
community_address: "none",
community_title: "Failed",
position: "",
},
]);
toast("error", "Failed to load communities");
});
@ -57,13 +74,13 @@ export default function ConversationProvider(props: {
};
}, [send]);
const value = React.useMemo(
() => ({ conversations, communities }),
[communities, conversations],
);
return (
<ConversationContext.Provider value={value}>
<ConversationContext.Provider
value={{
conversations,
communities,
}}
>
{props.children}
</ConversationContext.Provider>
);

View file

@ -5,6 +5,7 @@ import { useConversation } from "../context";
import Switch from "./switch";
import ConversationModal from "../modal/conversation";
import CommunityModal from "../modal/community";
import { Loader2 } from "lucide-react";
/**
* Executes List.
@ -22,7 +23,9 @@ export default function List() {
const virtualizer = useVirtualizer({
count:
category === "conversations" ? conversations.length : communities.length,
category === "conversations"
? conversations?.length || 0
: communities?.length || 0,
estimateSize: () => 60,
getScrollElement: () => scrollRef.current,
});
@ -41,32 +44,45 @@ export default function List() {
height: `${virtualizer.getTotalSize()}px`,
}}
>
{virtualizer.getVirtualItems().map((virtualItem) => {
const itemKey = `${category}-${virtualItem.index}`;
{communities === null || conversations === null ? (
<div className="flex items-center justify-center h-full pt-5">
<p className="text-foreground/45 flex gap-1 items-center justify-center">
<Loader2 size={18} className="animate-spin" />
Loading...
</p>
</div>
) : null}
return (
<div
key={itemKey}
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
transform: `translateY(${virtualItem.start}px)`,
}}
>
{category === "conversations" ? (
conversations[virtualItem.index] ? (
<ConversationModal
userId={conversations[virtualItem.index].user_id}
{communities &&
conversations &&
virtualizer.getVirtualItems().map((virtualItem) => {
const itemKey = `${category}-${virtualItem.index}`;
return (
<div
key={itemKey}
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
transform: `translateY(${virtualItem.start}px)`,
}}
>
{category === "conversations" ? (
conversations[virtualItem.index] ? (
<ConversationModal
userId={conversations[virtualItem.index].user_id}
/>
) : null
) : communities[virtualItem.index] ? (
<CommunityModal
community={communities[virtualItem.index]}
/>
) : null
) : communities[virtualItem.index] ? (
<CommunityModal community={communities[virtualItem.index]} />
) : null}
</div>
);
})}
) : null}
</div>
);
})}
</div>
</div>
</div>