Skip to content

Commit 726139e

Browse files
committed
feat: added integration of groups on /messages route.
1 parent f1884d1 commit 726139e

File tree

4 files changed

+157
-123
lines changed

4 files changed

+157
-123
lines changed

platforms/pictique/src/lib/fragments/Group/Group.svelte

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,33 @@
66
interface IGroupProps extends HTMLAttributes<HTMLButtonElement> {
77
avatar: string;
88
name: string;
9+
text: string;
910
unread?: boolean;
1011
callback: () => void;
1112
}
1213
13-
const { avatar, name, unread = false, callback, ...restProps }: IGroupProps = $props();
14+
const { avatar, name, unread = false, text, callback, ...restProps }: IGroupProps = $props();
15+
16+
const messageText = $derived(text.length < 80 ? text : `${text.substring(0, 80)}...`);
1417
</script>
1518

1619
<button
1720
{...restProps}
1821
class={cn([
19-
'relative flex w-full cursor-pointer items-center gap-3 rounded-lg px-2 py-4',
22+
'relative flex w-full cursor-pointer items-center gap-3 rounded-lg py-4',
2023
restProps.class
2124
])}
2225
onclick={callback}
2326
>
2427
<Avatar src={avatar} alt="Group Avatar" size="md" />
25-
<span class="flex w-full items-center justify-between">
26-
<h2 class="text-left font-medium">{name}</h2>
27-
{#if unread}
28-
<span class="h-2 w-2 rounded-full bg-blue-500"></span>
29-
{/if}
28+
<span class="flex w-full flex-col items-start justify-end gap-1">
29+
<span class="flex w-full items-center justify-between">
30+
<h2 class="text-left font-medium">{name}</h2>
31+
{#if unread}
32+
<span class="h-2 w-2 rounded-full bg-blue-500"></span>
33+
{/if}
34+
</span>
35+
<p class="text-start text-black/60">{messageText}</p>
3036
</span>
3137
</button>
3238

Lines changed: 93 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,120 @@
1-
import type { SVGAttributes } from 'svelte/elements';
1+
import type { SVGAttributes } from "svelte/elements";
22

33
export interface ISvgProps extends SVGAttributes<SVGElement> {
4-
size?: number | string;
5-
color?: string;
4+
size?: number | string;
5+
color?: string;
66
}
77

88
export type CommentType = {
9-
commentId: string;
10-
name: string;
11-
userImgSrc: string;
12-
comment: string;
13-
isUpVoted: boolean;
14-
isDownVoted: boolean;
15-
upVotes: number;
16-
time: string;
17-
replies: CommentType[];
9+
commentId: string;
10+
name: string;
11+
userImgSrc: string;
12+
comment: string;
13+
isUpVoted: boolean;
14+
isDownVoted: boolean;
15+
upVotes: number;
16+
time: string;
17+
replies: CommentType[];
1818
};
1919

2020
export type PostData = {
21-
createdAt: string | number | Date;
22-
id: string;
23-
avatar: string;
24-
userId: string;
25-
username: string;
26-
imgUris: string[];
27-
caption: string;
28-
time: string;
29-
count: {
30-
likes: number;
31-
comments: number;
32-
};
21+
createdAt: string | number | Date;
22+
id: string;
23+
avatar: string;
24+
userId: string;
25+
username: string;
26+
imgUris: string[];
27+
caption: string;
28+
time: string;
29+
count: {
30+
likes: number;
31+
comments: number;
32+
};
3333
};
3434

3535
export interface Post {
36-
id: string;
37-
text: string;
38-
images: string[];
39-
author: {
40-
id: string;
41-
handle: string;
42-
name: string;
43-
avatarUrl: string;
44-
};
45-
createdAt: string;
46-
likedBy: userProfile[];
47-
comments: {
48-
id: string;
49-
text: string;
50-
author: {
51-
id: string;
52-
handle: string;
53-
name: string;
54-
avatarUrl: string;
55-
};
56-
createdAt: string;
57-
}[];
36+
id: string;
37+
text: string;
38+
images: string[];
39+
author: {
40+
id: string;
41+
handle: string;
42+
name: string;
43+
avatarUrl: string;
44+
};
45+
createdAt: string;
46+
likedBy: userProfile[];
47+
comments: {
48+
id: string;
49+
text: string;
50+
author: {
51+
id: string;
52+
handle: string;
53+
name: string;
54+
avatarUrl: string;
55+
};
56+
createdAt: string;
57+
}[];
5858
}
5959

6060
export type userProfile = {
61-
id: string;
62-
handle: string;
63-
name: string;
64-
description: string;
65-
avatarUrl: string;
66-
totalPosts: number;
67-
followers: number;
68-
following: number;
69-
posts: PostData[];
70-
username: string;
61+
id: string;
62+
handle: string;
63+
name: string;
64+
description: string;
65+
avatarUrl: string;
66+
totalPosts: number;
67+
followers: number;
68+
following: number;
69+
posts: PostData[];
70+
username: string;
7171
};
7272

7373
export type Image = {
74-
url: string;
75-
alt: string;
74+
url: string;
75+
alt: string;
7676
};
7777

7878
export type GroupInfo = {
79-
id: string;
80-
name: string;
81-
avatar: string;
79+
id: string;
80+
name?: string;
81+
avatar: string;
82+
text: string;
83+
unread: boolean;
84+
participants: {
85+
id: string;
86+
name?: string;
87+
handle?: string;
88+
ename?: string;
89+
avatarUrl: string;
90+
}[];
8291
};
8392

8493
export type Chat = {
85-
id: string;
86-
avatar: string;
87-
handle: string;
88-
unread: boolean;
89-
text: string;
90-
participants: {
91-
id: string;
92-
name?: string;
93-
handle?: string;
94-
ename?: string;
95-
avatarUrl: string;
96-
}[];
97-
latestMessage: {
98-
text: string;
99-
isRead: boolean;
100-
};
94+
id: string;
95+
avatar: string;
96+
name?: string;
97+
unread: boolean;
98+
text: string;
99+
participants: {
100+
id: string;
101+
name?: string;
102+
handle?: string;
103+
ename?: string;
104+
avatarUrl: string;
105+
}[];
106+
latestMessage: {
107+
text: string;
108+
isRead: boolean;
109+
};
101110
};
102111

103112
export type MessageType = {
104-
id: string;
105-
avatar: string;
106-
handle: string;
107-
unread: boolean;
108-
text: string;
109-
name: string;
110-
username: string;
113+
id: string;
114+
avatar: string;
115+
handle: string;
116+
unread: boolean;
117+
text: string;
118+
name: string;
119+
username: string;
111120
};

platforms/pictique/src/routes/(protected)/+layout.svelte

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@
109109
<section class="hide-scrollbar h-[100dvh] overflow-y-auto px-4 pb-8 md:px-8 md:pt-8">
110110
<div class="flex flex-col">
111111
<Header
112-
variant={route === `/messages/${idFromParams}` || route.includes('/post')
112+
variant={route === `/messages/${idFromParams}` ||
113+
route.includes('/post') ||
114+
route.includes('/group')
113115
? 'secondary'
114116
: route.includes('profile')
115117
? 'tertiary'
@@ -127,7 +129,7 @@
127129
</section>
128130
{#if route === '/home' || route === '/messages'}
129131
<aside
130-
class="hide-scrollbar relative hidden h-[100dvh] overflow-y-scroll border border-e-0 border-t-0 border-b-0 border-s-gray-200 px-8 pt-14 md:block"
132+
class="hide-scrollbar relative hidden h-[100dvh] overflow-y-scroll border border-b-0 border-e-0 border-t-0 border-s-gray-200 px-8 pt-14 md:block"
131133
>
132134
{#if route === '/home'}
133135
{#if showComments.value}
@@ -160,7 +162,7 @@
160162
{/each}
161163
{/if}
162164
<MessageInput
163-
class="sticky start-0 bottom-4 mt-4 w-full px-2"
165+
class="sticky bottom-4 start-0 mt-4 w-full px-2"
164166
variant="comment"
165167
src={profile?.avatarUrl ?? '/images/user.png'}
166168
bind:value={commentValue}

platforms/pictique/src/routes/(protected)/messages/+page.svelte

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,40 @@
2323
const { data } = await apiClient.get<{ chats: Chat[] }>('/api/chats');
2424
const { data: userData } = await apiClient.get('/api/users');
2525
currentUserId = userData.id;
26-
27-
messages = data.chats.map((c) => {
28-
const members = c.participants.filter((u) => u.id !== userData.id);
29-
const memberNames = members.map((m) => m.name ?? m.handle ?? m.ename);
30-
const avatar =
31-
members.length > 1
32-
? 'https://cdn.jsdelivr.net/npm/[email protected]/icons/people-fill.svg'
33-
: members[0].avatarUrl;
34-
return {
35-
id: c.id,
36-
avatar,
37-
username: c.handle ?? memberNames.join(', '),
38-
unread: c.latestMessage ? c.latestMessage.isRead : false,
39-
text: c.latestMessage?.text ?? 'No message yet',
40-
handle: c.handle ?? memberNames.join(', '),
41-
name: c.handle ?? memberNames.join(', ')
42-
};
43-
});
26+
console.log(data.chats);
27+
messages = data.chats
28+
.filter((c) => c.participants.length <= 2)
29+
.map((c) => {
30+
const members = c.participants.filter((u) => u.id !== userData.id);
31+
const memberNames = members.map((m) => m.name ?? m.handle ?? m.ename);
32+
const avatar =
33+
members.length > 1
34+
? 'https://cdn.jsdelivr.net/npm/[email protected]/icons/people-fill.svg'
35+
: members[0].avatarUrl;
36+
return {
37+
id: c.id,
38+
avatar,
39+
username: c.name ?? memberNames.join(', '),
40+
unread: c.latestMessage ? c.latestMessage.isRead : false,
41+
text: c.latestMessage?.text ?? 'No message yet',
42+
handle: c.name ?? memberNames.join(', '),
43+
name: c.name ?? memberNames.join(', ')
44+
};
45+
});
46+
groups = data.chats
47+
.filter((c) => c.participants.length > 2)
48+
.map((c) => {
49+
console.log(c.participants);
50+
const avatar = '/images/group.png';
51+
return {
52+
id: c.id,
53+
avatar,
54+
unread: c.latestMessage ? c.latestMessage.isRead : false,
55+
text: c.latestMessage?.text ?? 'No message yet',
56+
participants: c.participants,
57+
name: c.name
58+
};
59+
});
4460
}
4561
4662
onMount(async () => {
@@ -79,14 +95,11 @@
7995
} else {
8096
const groupMembers = allMembers.filter((m) => selectedMembers.includes(m.id));
8197
const groupName = groupMembers.map((m) => m.name ?? m.handle ?? m.ename).join(', ');
82-
groups = [
83-
...groups,
84-
{
85-
id: Math.random().toString(36).slice(2),
86-
name: groupName,
87-
avatar: '/images/group.png'
88-
}
89-
];
98+
await apiClient.post('/api/chats', {
99+
name: groupName,
100+
participantIds: selectedMembers
101+
});
102+
await loadMessages(); // 🛠️ Refresh to include the new group
90103
}
91104
} catch (err) {
92105
console.error('Failed to create chat:', err);
@@ -128,13 +141,17 @@
128141
{/if}
129142

130143
{#if groups.length > 0}
131-
<h3 class="text-md mt-6 mb-2 font-semibold text-gray-700">Groups</h3>
144+
<h3 class="text-md mb-2 mt-6 font-semibold text-gray-700">Groups</h3>
132145
{#each groups as group}
133146
<Group
134147
name={group.name || 'New Group'}
135148
avatar={group.avatar}
136-
unread={true}
137-
callback={() => goto(`/group/${group.id}`)}
149+
unread={group.unread}
150+
text={group.text}
151+
callback={() => {
152+
heading.set(group.name || 'New Group');
153+
goto(`/group/${group.id}`);
154+
}}
138155
/>
139156
{/each}
140157
{:else if messages.length === 0}

0 commit comments

Comments
 (0)