Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

moving latest updates #6

Merged
merged 3 commits into from
Sep 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
191 changes: 191 additions & 0 deletions apps/shinkai-app/src/components/ChatMessages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import {
getLastMessagesFromInbox,
getLastUnreadMessagesFromInbox,
} from '@shinkai/shinkai-message-ts/api/methods';
import { ShinkaiMessage } from '@shinkai/shinkai-message-ts/models';
import { IonList, IonItem, IonButton } from '@ionic/react';
import Avatar from '../components/ui/Avatar';
import { cn } from '../theme/lib/utils';
import { IonContentCustom } from './ui/Layout';
import { calculateMessageHash } from '@shinkai/shinkai-message-ts/utils/shinkai_message_handler';
import { RootState } from '../store';
import { receiveLastMessagesFromInbox } from '../store/actions';

interface ChatMessagesProps {
deserializedId: string;
}

const ChatMessages: React.FC<ChatMessagesProps> = ({ deserializedId }) => {
console.log('Loading ChatMessages.tsx');
const dispatch = useDispatch();
const setupDetailsState = useSelector(
(state: RootState) => state.setupDetails
);
const reduxMessages = useSelector(
(state: RootState) => state.messages.inboxes[deserializedId]
);

const [lastKey, setLastKey] = useState<string | undefined>(undefined);
const [mostRecentKey, setMostRecentKey] = useState<string | undefined>(
undefined
);
const [prevMessagesLength, setPrevMessagesLength] = useState(0);
const [hasMoreMessages, setHasMoreMessages] = useState(true);
const [messages, setMessages] = useState<ShinkaiMessage[]>([]);

useEffect(() => {
console.log('deserializedId:', deserializedId);
getLastMessagesFromInbox(
deserializedId,
10,
lastKey,
setupDetailsState
).then((messages) => {
dispatch(receiveLastMessagesFromInbox(deserializedId, messages));
});
}, [dispatch, setupDetailsState, deserializedId, lastKey]);

useEffect(() => {
const interval = setInterval(() => {
getLastUnreadMessagesFromInbox(
deserializedId,
10,
mostRecentKey,
setupDetailsState
).then((messages) => {
dispatch(receiveLastMessagesFromInbox(deserializedId, messages));
});
}, 5000); // 2000 milliseconds = 2 seconds
return () => clearInterval(interval);
}, [
dispatch,
deserializedId,
mostRecentKey,
setupDetailsState,
]);

useEffect(() => {
if (reduxMessages && reduxMessages.length > 0) {
// console.log("Redux Messages:", reduxMessages);
const lastMessage = reduxMessages[reduxMessages.length - 1];
console.log('Last Message:', lastMessage);
const timeKey = lastMessage.external_metadata.scheduled_time;
const hashKey = calculateMessageHash(lastMessage);
const lastMessageKey = `${timeKey}:::${hashKey}`;
setLastKey(lastMessageKey);

const mostRecentMessage = reduxMessages[0];
const mostRecentTimeKey =
mostRecentMessage.external_metadata.scheduled_time;
const mostRecentHashKey = calculateMessageHash(mostRecentMessage);
const mostRecentMessageKey = `${mostRecentTimeKey}:::${mostRecentHashKey}`;
setMostRecentKey(mostRecentMessageKey);

setMessages(reduxMessages);

if (reduxMessages.length - prevMessagesLength < 10) {
setHasMoreMessages(false);
}
setPrevMessagesLength(reduxMessages.length);
}
}, [reduxMessages, prevMessagesLength]);

const extractContent = (messageBody: any) => {
// TODO: extend it so it can be re-used by JobChat or normal Chat
if (messageBody && 'unencrypted' in messageBody) {
if ('unencrypted' in messageBody.unencrypted.message_data) {
return JSON.parse(
messageBody.unencrypted.message_data.unencrypted.message_raw_content
).content;
} else {
return JSON.parse(
messageBody.unencrypted.message_data.encrypted.content
).content;
}
} else if (messageBody?.encrypted) {
return JSON.parse(messageBody.encrypted.content).content;
}
return '';
};

return (
<IonContentCustom>
<div className="py-10 md:rounded-[1.25rem] bg-white dark:bg-slate-800">
{hasMoreMessages && (
<IonButton
onClick={() =>
dispatch(
getLastMessagesFromInbox(
deserializedId,
10,
lastKey,
setupDetailsState
// true
)
)
}
>
Load More
</IonButton>
)}
<IonList class="ion-list-chat p-0 divide-y divide-slate-200 dark:divide-slate-500/50 md:rounded=[1.25rem] ">
{messages &&
messages.slice().map((message, index) => {
const { shinkai_identity, profile, registration_name } =
setupDetailsState;

const localIdentity = `${profile}/device/${registration_name}`;
// console.log("Message:", message);
let isLocalMessage = false;
if (message.body && 'unencrypted' in message.body) {
isLocalMessage =
message.body.unencrypted.internal_metadata
.sender_subidentity === localIdentity;
}

return (
<IonItem
key={index}
lines="none"
className={cn(
'ion-item-chat relative w-full shadow',
isLocalMessage && 'isLocalMessage'
)}
>
<div className="px-2 py-4 flex gap-4 pb-10 w-full">
<Avatar
className="shrink-0 mr-4"
url={
isLocalMessage
? 'https://ui-avatars.com/api/?name=Me&background=FE6162&color=fff'
: 'https://ui-avatars.com/api/?name=O&background=363636&color=fff'
}
/>

<p>{extractContent(message.body)}</p>
{message?.external_metadata?.scheduled_time && (
<span className="absolute bottom-[5px] right-5 text-muted text-sm">
{new Date(
message.external_metadata.scheduled_time
).toLocaleString(undefined, {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
})}
</span>
)}
</div>
</IonItem>
);
})}
</IonList>
</div>
</IonContentCustom>
);
};

export default ChatMessages;
27 changes: 0 additions & 27 deletions apps/shinkai-app/src/features/chat/chatSlice.ts

This file was deleted.

15 changes: 9 additions & 6 deletions apps/shinkai-app/src/hooks/usetSetup.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
// hooks/useSetup.ts
import { useEffect } from "react";
import { useSelector } from "react-redux";
import { shallowEqual, useSelector } from "react-redux";
import { RootState } from "../store";
import { ApiConfig } from "@shinkai/shinkai-message-ts/api";

export const useSetup = () => {
const { setupDetailsState } = useSelector((state: RootState) => state);
const setupDetails = useSelector(
(state: RootState) => state.setupDetails,
shallowEqual
);

useEffect(() => {
console.log("Redux State:", setupDetailsState);
ApiConfig.getInstance().setEndpoint(setupDetailsState.node_address);
}, [setupDetailsState]);
};
console.log("Redux State:", setupDetails);
ApiConfig.getInstance().setEndpoint(setupDetails.node_address);
}, [setupDetails]);
};
15 changes: 10 additions & 5 deletions apps/shinkai-app/src/pages/AddAgent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@ import {
import { useEffect, useState } from "react";
import { IonContentCustom, IonHeaderCustom } from "../components/ui/Layout";
import Button from "../components/ui/Button";
import Input from "../components/ui/Input";
import { useDispatch, useSelector } from "react-redux";
import { RootState } from "../store";
import { SerializedAgent, AgentAPIModel } from "@shinkai/shinkai-message-ts/models";
import { addAgent } from "@shinkai/shinkai-message-ts/api";
import { useSetup } from "../hooks/usetSetup";
import { useHistory } from 'react-router-dom';

const AddAgent: React.FC = () => {
useSetup();
const dispatch = useDispatch();
const setupDetailsState = useSelector(
(state: RootState) => state.setupDetailsState
(state: RootState) => state.setupDetails
);
const [agent, setAgent] = useState<Partial<SerializedAgent>>({
perform_locally: false,
Expand Down Expand Up @@ -70,7 +70,7 @@ const AddAgent: React.FC = () => {
});
};

const handleSubmit = () => {
const handleSubmit = async () => {
const { shinkai_identity, profile } = setupDetailsState;
const node_name = shinkai_identity;

Expand All @@ -82,13 +82,18 @@ const AddAgent: React.FC = () => {
}

console.log("Submitting agent:", agent);
addAgent(

const resp = await addAgent(
profile,
node_name,
agent as SerializedAgent,
setupDetailsState
);
if (resp) {
// TODO: show a success toast
// eslint-disable-next-line no-restricted-globals
history.back();
}
};

return (
Expand Down
4 changes: 2 additions & 2 deletions apps/shinkai-app/src/pages/AdminCommands.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { useSetup } from "../hooks/usetSetup";
const AdminCommands: React.FC = () => {
useSetup();
const setupDetailsState = useSelector(
(state: RootState) => state.setupDetailsState
(state: RootState) => state.setupDetails
);
const [showCodeRegistrationActionSheet, setShowCodeRegistrationActionSheet] =
useState(false);
Expand All @@ -36,7 +36,7 @@ const AdminCommands: React.FC = () => {
const [profileName, setProfileName] = useState("");
const dispatch = useDispatch();
const registrationCode = useSelector(
(state: RootState) => state.registrationCode
(state: RootState) => state.other.registrationCode
);
const commands = [
"Get Peers",
Expand Down
10 changes: 5 additions & 5 deletions apps/shinkai-app/src/pages/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import React, { useEffect, useRef, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
getLastMessagesFromInbox,
createChatWithMessage,
sendTextMessageWithInbox,
} from '@shinkai/shinkai-message-ts/api';
import { RootState } from '../store';
Expand All @@ -42,6 +41,7 @@ import {
IonHeaderCustom,
} from '../components/ui/Layout';
import { addMessageToInbox, receiveLastMessagesFromInbox, receiveLoadMoreMessagesFromInbox } from '../store/actions';
import { RECEIVE_LAST_MESSAGES_FROM_INBOX } from '../store/types';

const parseDate = (dateString: string) => {
return new Date(dateString);
Expand All @@ -53,7 +53,7 @@ const Chat: React.FC = () => {

const dispatch = useDispatch();
const setupDetailsState = useSelector(
(state: RootState) => state.setupDetailsState
(state: RootState) => state.setupDetails
);

const { id } = useParams<{ id: string }>();
Expand All @@ -64,7 +64,7 @@ const Chat: React.FC = () => {
const [prevMessagesLength, setPrevMessagesLength] = useState(0);

const reduxMessages = useSelector(
(state: RootState) => state.inboxes[deserializedId]
(state: RootState) => state.messages.inboxes[deserializedId]
);

const [messages, setMessages] = useState<ShinkaiMessage[]>([]);
Expand All @@ -78,9 +78,9 @@ const Chat: React.FC = () => {
console.log('deserializedId:', deserializedId);
getLastMessagesFromInbox(deserializedId, 10, lastKey, setupDetailsState).then((messages) => {
console.log("receiveLastMessagesFromInbox Response:", messages);
dispatch(receiveLastMessagesFromInbox(deserializedId, messages));
dispatch({ type: RECEIVE_LAST_MESSAGES_FROM_INBOX, payload: messages });
});
}, [id, dispatch, setupDetailsState]);
}, [id, dispatch, setupDetailsState, deserializedId, lastKey]);

useEffect(() => {
if (reduxMessages && reduxMessages.length > 0) {
Expand Down
7 changes: 2 additions & 5 deletions apps/shinkai-app/src/pages/Connect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,11 @@ import {
generateSignatureKeys,
} from "@shinkai/shinkai-message-ts/utils";
import { QRSetupData } from "../models/QRSetupData";
import { SetupDetailsState } from "../store/reducers";
import { InputCustomEvent } from "@ionic/core/dist/types/components/input/input-interface";
import { cn } from "../theme/lib/utils";
import Button from "../components/ui/Button";
import { IonHeaderCustom } from "../components/ui/Layout";
import Input from "../components/ui/Input";
import { scan, cloudUpload, checkmarkSharp } from "ionicons/icons";
import { useRegistrationCode } from "../store/actions";
import { SetupDetailsState } from "../store/reducers/setupDetailsReducer";

export type MergedSetupType = SetupDetailsState & QRSetupData;

Expand Down Expand Up @@ -58,7 +55,7 @@ const Connect: React.FC = () => {
const [error, setError] = useState<string | null>(null);
const dispatch = useDispatch<AppDispatch>();
const history = useHistory();
const errorFromState = useSelector((state: RootState) => state.error);
const errorFromState = useSelector((state: RootState) => state.other.error);

// Generate keys when the component mounts
useEffect(() => {
Expand Down
Loading
Loading