Skip to content
Closed
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
3ad28dd
feat: join chat + fetch channels list
frdomovic Nov 13, 2025
a87b5ed
feat: channel details + members in navbar
frdomovic Nov 13, 2025
3c4eabe
feat: user management + create channel
frdomovic Nov 13, 2025
f61b70c
feat: channel invitation
frdomovic Nov 14, 2025
1eb869a
feat: cleanup
frdomovic Nov 14, 2025
3d38a29
feat: add search public channels
frdomovic Nov 14, 2025
caf7e5c
feat: init dm version
frdomovic Nov 15, 2025
fb87b02
feat: add channels acls
frdomovic Nov 17, 2025
f45c4c4
feat: remove user logic
frdomovic Nov 17, 2025
8c51c88
feat: message handler
frdomovic Nov 17, 2025
888fed3
feat: various UI fixes
frdomovic Nov 19, 2025
760fee5
fix: dm creations
frdomovic Nov 20, 2025
686ff0e
feat: blobs - mentions
frdomovic Nov 21, 2025
98386d5
fix: mentions on edit
frdomovic Nov 21, 2025
1dd0198
fix: channels + messages
frdomovic Nov 21, 2025
446fa88
feat: insync channel operations
frdomovic Nov 24, 2025
39ed78f
feat: wss connection
frdomovic Nov 25, 2025
d2b0fbd
fix: temp msg solution
frdomovic Nov 25, 2025
f852937
fix: message propagation on edit delete
frdomovic Nov 25, 2025
fc558c0
feat: readonly channels
frdomovic Nov 26, 2025
5d1a34c
feat: cleanup logs
frdomovic Nov 26, 2025
21dd1e7
feat: notifications + messages
frdomovic Nov 26, 2025
36b6e26
fix: error checks and displays
frdomovic Nov 27, 2025
6cfbfbc
feat: hide search messages
frdomovic Nov 27, 2025
4952041
feat: update channel create response handling
frdomovic Nov 28, 2025
fd67506
feat: app build
frdomovic Nov 28, 2025
a138e1d
feat: seach option fe
frdomovic Nov 28, 2025
97afffe
fix: paginated refetch in threads
frdomovic Dec 3, 2025
6df5aff
refactor: simplify argsJson structure in ClientApiDataSource methods
rtb-12 Dec 9, 2025
05f68fd
fix: build
frdomovic Jan 5, 2026
2763dac
feat: bump version
frdomovic Jan 5, 2026
1f8bc6d
feat: add logic-js files
frdomovic Jan 7, 2026
96eb95e
fix: broken app
frdomovic Jan 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/dev-dist/sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ define(['./workbox-c6a197bf'], (function (workbox) { 'use strict';
"revision": "3ca0b8505b4bec776b69afdba2768812"
}, {
"url": "index.html",
"revision": "0.7nelul30iak"
"revision": "0.h9iemhdglkg"
}], {});
workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
Expand Down
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
},
"dependencies": {
"@braintree/sanitize-url": "^7.1.1",
"@calimero-network/calimero-client": "1.23.1",
"@calimero-network/calimero-client": "1.24.1",
"@calimero-network/mero-icons": "^0.0.6",
"@calimero-network/mero-ui": "1.4.0",
"@radix-ui/react-accordion": "^1.2.11",
Expand Down
10 changes: 5 additions & 5 deletions app/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

216 changes: 173 additions & 43 deletions app/src/api/clientApi.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import type { ApiResponse } from "@calimero-network/calimero-client";
import type { HashMap } from "../types/Common";
import type { MessageId } from "../components/virtualized-chat";

export enum ChannelType {
PUBLIC = "Public",
PRIVATE = "Private",
GROUP = "Default",
PUBLIC = "public",
PRIVATE = "private",
GROUP = "default",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ChannelType enum change breaks private channel detection

The ChannelType enum values were changed from PascalCase ("Private") to lowercase ("private"), but existing code in DetailsDropdown.tsx and DetailsContainer.tsx still compares against the old PascalCase value "Private". This means private channels will not be detected correctly, causing the wrong icon (public hashtag instead of lock) to display for private channels throughout the UI.

Additional Locations (2)

Fix in Cursor Fix in Web

}

export interface Channel {
name: string;
}

export type UserId = string;
export type Username = string;

export interface CreateChannelProps {
channel: Channel;
channel_type: ChannelType;
read_only: boolean;
readOnly: boolean;
moderators: UserId[];
links_allowed: boolean;
created_at: number;
Expand All @@ -35,7 +37,10 @@ export interface ChannelInfo {
unread_mentions: number;
}

export type Channels = Map<string, ChannelInfo>;
export type AllChannelsResponse = {
availablePublic: ChannelDataResponse[];
joined: ChannelDataResponse[];
};

interface ChannelOperationProps {
channel: Channel;
Expand All @@ -46,6 +51,7 @@ export type GetChannelInfoProps = ChannelOperationProps;
export type GetNonMemberUsersProps = ChannelOperationProps;
export type JoinChannelProps = ChannelOperationProps;
export type LeaveChannelProps = ChannelOperationProps;
export type DeleteChannelProps = ChannelOperationProps;

export interface GetMessagesProps {
group: Channel;
Expand All @@ -56,25 +62,28 @@ export interface GetMessagesProps {
dm_identity?: UserId;
refetch_context_id?: string;
refetch_identity?: UserId;
search_term?: string;
searchTerm?: string;
}

export interface Message {
id: string;
sender: string;
sender_username: string;
senderUsername: string;
text: string;
timestamp: number;
deleted?: boolean;
edited_on?: number;
editedAt?: number;
reactions: HashMap<string, UserId[]>;
thread_count: number;
thread_last_timestamp: number;
threadCount: number;
threadLastTimestamp: number;
group?: string;
files?: AttachmentResponse[];
images?: AttachmentResponse[];
mentions: UserId[];
mentionUsernames: string[];
}


export interface MessageWithReactions extends Message {
reactions: HashMap<string, UserId[]>;
}
Expand All @@ -94,6 +103,46 @@ export interface AttachmentResponse {
uploaded_at: number;
}

export interface MessageAttachments {
files?: AttachmentRequest[];
images?: AttachmentRequest[];
}

// New backend API types
export interface SendMessageArgs {
channelId: string;
text: string;
parentId?: string | null;
attachments?: MessageAttachments;
messageId?: string;
}

export interface GetMessagesArgs {
channelId: string;
parentId?: string | null;
limit?: number;
offset?: number;
}

export interface EditMessageArgs {
channelId: string;
messageId: string;
text: string;
parentId?: string | null;
}

export interface DeleteMessageArgs {
channelId: string;
messageId: string;
parentId?: string | null;
}

export interface UpdateReactionArgs {
messageId: string;
emoji: string;
add: boolean;
}

export interface SendMessageProps {
group: Channel;
message: string;
Expand All @@ -113,9 +162,42 @@ export interface FullMessageResponse {
start_position: number;
}

export interface GetMessagesResponse {
result: { output: { result: FullMessageResponse } };
}

export interface InviteToChannelProps {
channel: Channel;
user: UserId;
username?: Username;
}

export type ChannelId = string;

export interface ChannelMembershipInput {
channelId: ChannelId;
userId: UserId;
username?: Username;
}

export interface ModeratorInput {
channelId: ChannelId;
userId: UserId;
}

export interface PromoteModeratorProps {
channel: Channel;
user: UserId;
}

export interface DemoteModeratorProps {
channel: Channel;
user: UserId;
}

export interface RemoveUserFromChannelProps {
channel: Channel;
user: UserId;
}

export interface DMChatInfo {
Expand All @@ -137,6 +219,25 @@ export interface DMChatInfo {
unread_messages: number;
}

export interface DMrawObject {
channelType: ChannelType;
contextId: string;
createdAt: number;
createdBy: UserId;
channelUser: UserId;
otherIdentityNew: UserId;
otherIdentityOld: UserId;
otherUsername: string;
ownIdentity: UserId;
ownIdentityOld: UserId;
ownUsername: string;
didJoin: boolean;
invitationPayload: string;
oldHash: string;
newHash: string;
unreadMessages: number;
}

export interface CreateDmProps {
context_id: string;
context_hash: string;
Expand Down Expand Up @@ -206,18 +307,17 @@ export interface DeleteDMProps {
}

export interface ReadMessageProps {
channel: Channel;
timestamp: number;
channelId: string;
messageId: string;
}

export interface UpdateDmHashProps {
sender_id: UserId;
other_user_id: UserId;
new_hash: string;
newHash: string;
dmContextId: string;
}

export interface ReadDmProps {
other_user_id: UserId;
dmContextId: string;
}

export interface GetDmUnreadCountProps {
Expand All @@ -234,34 +334,58 @@ export type GetTotalDmUnreadCountProps = Record<string, never>;

export type MarkAllDmsAsReadProps = Record<string, never>;

export interface ChannelMember {
publicKey: string;
username: string;
}

export interface ChannelDataResponse {
channelId: string;
createdAt: string;
createdBy: string;
createdByUsername: string;
type: ChannelType;
members: ChannelMember[];
moderators: ChannelMember[];
readOnly: boolean;
unreadMessages: {
count: number;
mentions: number;
};
}

export enum ClientMethod {
JOIN_CHAT = "join_chat",
CREATE_CHANNEL = "create_channel",
GET_CHANNELS = "get_channels",
GET_ALL_CHANNELS_SEARCH = "get_all_channels",
GET_CHANNEL_MEMBERS = "get_channel_members",
JOIN_CHAT = "joinChat",
CREATE_CHANNEL = "createChannel",
GET_CHANNELS = "getChannels",
GET_ALL_CHANNELS_SEARCH = "getChannelDirectory",
GET_CHANNEL_MEMBERS = "abc",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Placeholder "abc" used for API method name

The GET_CHANNEL_MEMBERS enum value is set to "abc". This placeholder isn't a valid API method name, so calls to getChannelMembers will fail because the backend won't recognize it.

Fix in Cursor Fix in Web

GET_CHANNEL_INFO = "get_channel_info",
INVITE_TO_CHANNEL = "invite_to_channel",
GET_INVITE_USERS = "get_non_member_users",
JOIN_CHANNEL = "join_channel",
LEAVE_CHANNEL = "leave_channel",
GET_MESSAGES = "get_messages",
SEND_MESSAGE = "send_message",
GET_DMS = "get_dms",
INVITE_TO_CHANNEL = "addUserToChannel",
GET_INVITE_USERS = "getInvitees",
JOIN_CHANNEL = "joinPublicChannel",
LEAVE_CHANNEL = "leaveChannel",
DELETE_CHANNEL = "deleteChannel",
PROMOTE_MODERATOR = "promoteModerator",
DEMOTE_MODERATOR = "demoteModerator",
REMOVE_USER_FROM_CHANNEL = "removeUserFromChannel",
GET_MESSAGES = "getMessages",
SEND_MESSAGE = "sendMessage",
GET_DMS = "getDMs",
GET_CHAT_MEMBERS = "get_chat_members",
CREATE_DM = "create_dm_chat",
UPDATE_REACTION = "update_reaction",
DELETE_MESSAGE = "delete_message",
EDIT_MESSAGE = "edit_message",
UPDATE_NEW_IDENTITY = "update_new_identity",
CREATE_DM = "createDMChat",
UPDATE_REACTION = "updateReaction",
DELETE_MESSAGE = "deleteMessage",
EDIT_MESSAGE = "editMessage",
UPDATE_NEW_IDENTITY = "updateNewIdentity",
UPDATE_INVITATION_PAYLOAD = "update_invitation_payload",
ACCEPT_INVITATION = "accept_invitation",
DELETE_DM = "delete_dm",
GET_USERNAME = "get_username",
GET_CHAT_USERNAMES = "get_chat_usernames",
READ_MESSAGE = "mark_messages_as_read",
UPDATE_DM_HASH = "update_dm_hashes",
READ_DM = "mark_dm_as_read",
DELETE_DM = "deleteDM",
GET_USERNAME = "getUsername",
GET_CHAT_USERNAMES = "getMembers",
READ_MESSAGE = "readMessage",
UPDATE_DM_HASH = "updateDmHash",
READ_DM = "readDm",
GET_DM_UNREAD_COUNT = "get_dm_unread_count",
GET_TOTAL_DM_UNREAD_COUNT = "get_total_dm_unread_count",
GET_DM_IDENTITY_BY_CONTEXT = "get_dm_identity_by_context",
Expand All @@ -271,18 +395,24 @@ export enum ClientMethod {
export interface ClientApi {
joinChat(props: JoinChatProps): ApiResponse<string>;
createChannel(props: CreateChannelProps): ApiResponse<CreateChannelResponse>;
getChannels(): ApiResponse<Channels>;
getAllChannelsSearch(): ApiResponse<Channels>;
getChannels(): ApiResponse<ChannelDataResponse[]>;
getAllChannelsSearch(): ApiResponse<AllChannelsResponse>;
getChannelMembers(
props: GetChannelMembersProps,
): ApiResponse<Map<string, string>>;
getChannelInfo(props: GetChannelInfoProps): ApiResponse<ChannelInfo>;
inviteToChannel(props: InviteToChannelProps): ApiResponse<string>;
getNonMemberUsers(props: GetNonMemberUsersProps): ApiResponse<UserId[]>;
getNonMemberUsers(
props: GetNonMemberUsersProps,
): ApiResponse<Record<string, string>>;
joinChannel(props: JoinChannelProps): ApiResponse<string>;
leaveChannel(props: LeaveChannelProps): ApiResponse<string>;
deleteChannel(props: DeleteChannelProps): ApiResponse<string>;
promoteModerator(props: PromoteModeratorProps): ApiResponse<string>;
demoteModerator(props: DemoteModeratorProps): ApiResponse<string>;
removeUserFromChannel(props: RemoveUserFromChannelProps): ApiResponse<string>;
getMessages(props: GetMessagesProps): ApiResponse<FullMessageResponse>;
sendMessage(props: SendMessageProps): ApiResponse<Message>;
sendMessage(props: SendMessageProps): ApiResponse<{ id: MessageId }>;
getDms(): ApiResponse<DMChatInfo[]>;
getChatMembers(props: GetChatMembersProps): ApiResponse<Map<string, string>>;
createDm(props: CreateDmProps): ApiResponse<string>;
Expand Down
Loading