Skip to content

Commit 68cf7ed

Browse files
committed
fix: messages styling
1 parent e58cd16 commit 68cf7ed

File tree

8 files changed

+109
-35
lines changed

8 files changed

+109
-35
lines changed

src/lib/bluesky/hooks/useConversation.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useQuery } from '@tanstack/react-query';
22
import { useBlueskyStore } from '../store';
33
import { useAuth } from './useAuth';
4+
import { BSkyMessage } from '../types/BSkyMessage';
45

56
export function useConversation({ convoId }: { convoId: string }) {
67
const { agent, session } = useBlueskyStore();
@@ -19,7 +20,7 @@ export function useConversation({ convoId }: { convoId: string }) {
1920

2021
return response?.data.messages
2122
.slice(0)
22-
.sort((a, b) => new Date(a.sentAt as string).getTime() - new Date(b.sentAt as string).getTime());
23+
.sort((a, b) => new Date(a.sentAt as string).getTime() - new Date(b.sentAt as string).getTime()) as BSkyMessage[];
2324
},
2425
enabled: !!agent && isAuthenticated,
2526
});

src/lib/bluesky/hooks/useConversations.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useQuery } from '@tanstack/react-query';
22
import { useBlueskyStore } from '../store';
33
import { useAuth } from './useAuth';
4+
import { BSkyConvo } from '../types/BSkyConvo';
45

56
export function useConversations() {
67
const { agent, session } = useBlueskyStore();
@@ -16,7 +17,7 @@ export function useConversations() {
1617
// @ts-expect-error bsky_chat does in fact work
1718
const proxy = agent?.withProxy('bsky_chat', 'did:web:api.bsky.chat');
1819
const response = await proxy?.api.chat.bsky.convo.listConvos();
19-
return response?.data.convos;
20+
return response?.data.convos as BSkyConvo[];
2021
},
2122
enabled: !!agent && isAuthenticated,
2223
});

src/lib/bluesky/hooks/useNotifications.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import { useBlueskyStore } from '../store';
33
import { BSkyNotification } from '../types/BSkyNotification';
44

55
export function useNotifications() {
6-
const { agent } = useBlueskyStore();
6+
const { agent, isAuthenticated } = useBlueskyStore();
77

88
return useQuery({
99
queryKey: ['notifications'],
1010
queryFn: async () => {
11-
if (!agent) throw new Error('Not authenticated');
11+
if (!agent || !isAuthenticated) throw new Error('Not authenticated');
1212

1313
const response = await agent.api.app.bsky.notification.listNotifications();
1414
return response.data.notifications as BSkyNotification[];

src/lib/bluesky/types/BSkyConvo.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Static, Type } from '@sinclair/typebox';
2+
3+
export const BSkyConvo = Type.Object({
4+
id: Type.String(),
5+
rev: Type.String(),
6+
members: Type.Array(
7+
Type.Object({
8+
did: Type.String(),
9+
handle: Type.String(),
10+
displayName: Type.String(),
11+
avatar: Type.String(),
12+
associated: Type.Object({
13+
lists: Type.Number(),
14+
feedgens: Type.Number(),
15+
starterPacks: Type.Number(),
16+
labeler: Type.Boolean(),
17+
chat: Type.Object({
18+
allowIncoming: Type.String(),
19+
}),
20+
}),
21+
viewer: Type.Object({
22+
muted: Type.Boolean(),
23+
blockedBy: Type.Boolean(),
24+
following: Type.Optional(Type.String()),
25+
followedBy: Type.Optional(Type.String()),
26+
}),
27+
labels: Type.Array(Type.Unknown()),
28+
}),
29+
),
30+
lastMessage: Type.Object({
31+
$type: Type.Literal('chat.bsky.convo.defs#messageView'),
32+
id: Type.String(),
33+
rev: Type.String(),
34+
sender: Type.Object({
35+
did: Type.String(),
36+
}),
37+
text: Type.String(),
38+
sentAt: Type.String(),
39+
}),
40+
unreadCount: Type.Number(),
41+
opened: Type.Boolean(),
42+
muted: Type.Boolean(),
43+
});
44+
45+
export type BSkyConvo = Static<typeof BSkyConvo>;

src/lib/bluesky/types/BSkyMessage.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Static, Type } from '@sinclair/typebox';
2+
3+
export const BSkyMessage = Type.Object({
4+
id: Type.String(),
5+
rev: Type.String(),
6+
sender: Type.Object({
7+
did: Type.String(),
8+
}),
9+
text: Type.String(),
10+
sentAt: Type.String(),
11+
});
12+
13+
export type BSkyMessage = Static<typeof BSkyMessage>;

src/routes/__root.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ export const Route = createRootRoute({
1919
if (location.pathname.startsWith('/login')) {
2020
// if already authenticated, redirect to root
2121
const { isAuthenticated } = useBlueskyStore.getState();
22-
console.info('isAuthenticated', isAuthenticated);
2322
if (isAuthenticated) {
2423
throw redirect({ to: '/' });
2524
}

src/routes/messages/$convoId.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { createFileRoute } from '@tanstack/react-router';
22
import { useConversation } from '../../lib/bluesky/hooks/useConversation';
33
import { useTranslation } from 'react-i18next';
4-
import { Handle } from '../../components/ui/Handle';
5-
import { Debug } from '../../components/ui/Debug';
6-
import TimeAgo from 'react-timeago-i18n';
4+
import { cn } from '../../lib/utils';
5+
import { useBlueskyStore } from '../../lib/bluesky/store';
76

87
export const Route = createFileRoute('/messages/$convoId')({
98
component: RouteComponent,
@@ -12,17 +11,18 @@ export const Route = createFileRoute('/messages/$convoId')({
1211
function RouteComponent() {
1312
const { t } = useTranslation('app');
1413
const { convoId } = Route.useParams();
14+
const session = useBlueskyStore((state) => state.session);
1515
const { data: messages, isLoading } = useConversation({ convoId });
1616

1717
if (isLoading) return <div>{t('loading')}</div>;
1818

1919
return (
2020
<div className="flex flex-col gap-2 overflow-y-auto h-full">
2121
{messages?.map((message) => (
22-
<div key={message.id as string}>
23-
<Handle handle={(message.sender as { did: string }).did} />: {message.text as string} -{' '}
24-
<TimeAgo date={message.sentAt as string} />
25-
<Debug value={message} />
22+
<div className={cn('flex flex-col', message.sender.did === session?.did ? 'items-end' : 'items-start')}>
23+
<div className="bg-neutral-800 p-2 w-fit" key={message.id as string}>
24+
{message.text}
25+
</div>
2626
</div>
2727
))}
2828
</div>

src/routes/messages/index.tsx

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,38 +5,53 @@ import { Image } from '../../components/ui/Image';
55
import { cn } from '../../lib/utils';
66
import { useBlueskyStore } from '../../lib/bluesky/store';
77
import { Link } from '../../components/ui/Link';
8+
import { Debug } from '../../components/ui/Debug';
9+
import { BSkyConvo } from '../../lib/bluesky/types/BSkyConvo';
10+
import TimeAgo from 'react-timeago-i18n';
11+
import { Handle } from '../../components/ui/Handle';
12+
13+
function Conversation({ convo }: { convo: BSkyConvo }) {
14+
const session = useBlueskyStore((state) => state.session);
15+
const members = convo.members.filter((member) => member.did !== session?.did);
16+
17+
return (
18+
<>
19+
<Debug value={convo} />
20+
<Link key={convo.id} to="/messages/$convoId" params={{ convoId: convo.id }}>
21+
{members.map((member) => (
22+
<div className="flex gap-2" key={member.did}>
23+
<Image
24+
type="avatar"
25+
src={member.avatar}
26+
classNames={{
27+
image: cn(!member.associated?.labeler && 'rounded-full'),
28+
wrapper: 'size-24 aspect-square',
29+
}}
30+
/>
31+
<div className="flex flex-col">
32+
<div className="flex flex-row gap-2">
33+
<Handle handle={member.handle ?? member.did} />
34+
{' · '}
35+
<TimeAgo date={convo.lastMessage.sentAt} />
36+
</div>
37+
<div>{convo.lastMessage.text}</div>
38+
</div>
39+
</div>
40+
))}
41+
</Link>
42+
</>
43+
);
44+
}
845

946
export const Route = createFileRoute('/messages/')({
1047
component: Messages,
1148
});
1249

1350
function Messages() {
14-
const { session } = useBlueskyStore();
1551
const { data, isLoading } = useConversations();
1652
const { t } = useTranslation('app');
1753

1854
if (isLoading) return <div className="w-[550px] h-screen overflow-y-scroll">{t('loading')}</div>;
1955

20-
return (
21-
<div className="flex flex-col gap-2 overflow-y-auto h-screen">
22-
{data?.map((convo) => (
23-
<Link key={convo.id} to="/messages/$convoId" params={{ convoId: convo.id }}>
24-
{convo.members
25-
.filter((member) => member.did !== session?.did)
26-
.map((member) => (
27-
<div className="flex gap-2" key={member.did}>
28-
<Image
29-
type="avatar"
30-
src={member.avatar}
31-
classNames={{
32-
image: cn('size-24', member.associated?.labeler ? 'aspect-square' : 'rounded-full'),
33-
}}
34-
/>
35-
<div>{convo.lastMessage?.text as string}</div>
36-
</div>
37-
))}
38-
</Link>
39-
))}
40-
</div>
41-
);
56+
return <div className="flex flex-col gap-2">{data?.map((convo) => <Conversation key={convo.id} convo={convo} />)}</div>;
4257
}

0 commit comments

Comments
 (0)