mirror of
https://github.com/urbit/shrub.git
synced 2024-12-25 04:52:06 +03:00
chat: adding localstorage sync and cleanup
This commit is contained in:
parent
a00ab9e347
commit
fa5e974ad4
@ -4,6 +4,9 @@ module.exports = {
|
||||
'jest': true
|
||||
},
|
||||
rules: {
|
||||
// Because we use styled system, and use
|
||||
// the convention of each prop on a new line
|
||||
// we probably shouldn't keep this on
|
||||
'max-lines-per-function': ['off', {}]
|
||||
}
|
||||
};
|
||||
|
@ -113,7 +113,6 @@ interface ChatEditorProps {
|
||||
inCodeMode: boolean;
|
||||
placeholder: string;
|
||||
submit: (message: string) => void;
|
||||
onUnmount: (message: string) => void;
|
||||
onPaste: (codemirrorInstance, event: ClipboardEvent) => void;
|
||||
}
|
||||
|
||||
|
@ -5,18 +5,16 @@ import tokenizeMessage from '~/logic/lib/tokenizeMessage';
|
||||
import useStorage, { IuseStorage } from '~/logic/lib/useStorage';
|
||||
import { MOBILE_BROWSER_REGEX } from '~/logic/lib/util';
|
||||
import { withLocalState } from '~/logic/state/local';
|
||||
import withStorage from '~/views/components/withStorage';
|
||||
import ChatEditor, { CodeMirrorShim } from './ChatEditor';
|
||||
import airlock from '~/logic/api';
|
||||
import { ChatAvatar } from './ChatAvatar';
|
||||
import { useChatStore } from './ChatPane';
|
||||
import { useImperativeHandle } from 'react';
|
||||
|
||||
type ChatInputProps = PropsWithChildren<IuseStorage & {
|
||||
hideAvatars: boolean;
|
||||
ourContact?: Contact;
|
||||
placeholder: string;
|
||||
onUnmount(msg: string): void;
|
||||
deleteMessage(): void;
|
||||
onSubmit: (contents: Content[]) => void;
|
||||
}>;
|
||||
|
||||
@ -69,8 +67,9 @@ const MobileSubmitButton = ({ enabled, onSubmit }) => (
|
||||
</Box>
|
||||
);
|
||||
|
||||
export function ChatInput({ ourContact, hideAvatars, placeholder, onSubmit, onUnmount }: ChatInputProps) {
|
||||
export const ChatInput = React.forwardRef(({ ourContact, hideAvatars, placeholder, onSubmit }: ChatInputProps, ref) => {
|
||||
const chatEditor = useRef<CodeMirrorShim>(null);
|
||||
useImperativeHandle(ref, () => ({ uploadFiles }));
|
||||
const {
|
||||
message,
|
||||
setMessage
|
||||
@ -104,15 +103,6 @@ export function ChatInput({ ourContact, hideAvatars, placeholder, onSubmit, onUn
|
||||
chatEditor.current.focus();
|
||||
}
|
||||
|
||||
function uploadSuccess(url: string) {
|
||||
if (uploadingPaste) {
|
||||
chatEditor.current.setValue(url);
|
||||
setUploadingPaste(false);
|
||||
} else {
|
||||
onSubmit([{ url }]);
|
||||
}
|
||||
}
|
||||
|
||||
function onPaste(codemirrorInstance, event: React.ClipboardEvent<HTMLTextAreaElement>) {
|
||||
if (!event.clipboardData || !event.clipboardData.files.length) {
|
||||
return;
|
||||
@ -130,11 +120,24 @@ export function ChatInput({ ourContact, hideAvatars, placeholder, onSubmit, onUn
|
||||
}
|
||||
Array.from(files).forEach((file) => {
|
||||
uploadDefault(file)
|
||||
.then(this.uploadSuccess)
|
||||
.catch(this.uploadError);
|
||||
.then(uploadSuccess)
|
||||
.catch(uploadError);
|
||||
});
|
||||
}
|
||||
|
||||
function uploadSuccess(url: string) {
|
||||
if (uploadingPaste) {
|
||||
chatEditor.current.setValue(url);
|
||||
setUploadingPaste(false);
|
||||
} else {
|
||||
onSubmit([{ url }]);
|
||||
}
|
||||
}
|
||||
|
||||
function uploadError(error: Error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
return (
|
||||
<InputBox>
|
||||
<Row p='12px 4px 12px 12px' flexShrink={0} alignItems='center'>
|
||||
@ -144,7 +147,6 @@ export function ChatInput({ ourContact, hideAvatars, placeholder, onSubmit, onUn
|
||||
ref={chatEditor}
|
||||
inCodeMode={inCodeMode}
|
||||
submit={submit}
|
||||
onUnmount={onUnmount}
|
||||
onPaste={onPaste}
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
@ -181,11 +183,10 @@ export function ChatInput({ ourContact, hideAvatars, placeholder, onSubmit, onUn
|
||||
)}
|
||||
</InputBox>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore withLocalState prop passing weirdness
|
||||
export default withLocalState<Omit<ChatInputProps, keyof IuseStorage>, 'hideAvatars', ChatInput>(
|
||||
// @ts-ignore withLocalState prop passing weirdness
|
||||
withStorage<ChatInputProps, ChatInput>(ChatInput, { accept: 'image/*' }),
|
||||
ChatInput,
|
||||
['hideAvatars']
|
||||
);
|
||||
|
@ -1,39 +1,40 @@
|
||||
import { Col } from '@tlon/indigo-react';
|
||||
import { Content, Graph, Post } from '@urbit/api';
|
||||
import bigInt, { BigInteger } from 'big-integer';
|
||||
import _ from 'lodash';
|
||||
import React, { ReactElement, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import create from 'zustand';
|
||||
import { useFileDrag } from '~/logic/lib/useDrag';
|
||||
import { useLocalStorageState } from '~/logic/lib/useLocalStorageState';
|
||||
import { retrieve } from '~/logic/lib/useLocalStorageState';
|
||||
import { useOurContact } from '~/logic/state/contact';
|
||||
import { useGraphTimesent } from '~/logic/state/graph';
|
||||
import ShareProfile from '~/views/apps/chat/components/ShareProfile';
|
||||
import { Loading } from '~/views/components/Loading';
|
||||
import SubmitDragger from '~/views/components/SubmitDragger';
|
||||
import ChatInput, { ChatInput as NakedChatInput } from './ChatInput';
|
||||
import ChatInput from './ChatInput';
|
||||
import ChatWindow from './ChatWindow';
|
||||
|
||||
interface useChatStoreType {
|
||||
id: string;
|
||||
message: string;
|
||||
messageStore: Record<string, string>;
|
||||
setMessage: (message: string) => void;
|
||||
}
|
||||
|
||||
export const useChatStore = create<useChatStoreType>(set => ({
|
||||
const unsentKey = 'chat-unsent';
|
||||
|
||||
export const useChatStore = create<useChatStoreType>((set, get) => ({
|
||||
id: '',
|
||||
message: '',
|
||||
setMessage: (message: string) => set({ message })
|
||||
messageStore: retrieve(unsentKey, {}),
|
||||
setMessage: (message: string) => {
|
||||
const store = get().messageStore;
|
||||
store[get().id] = message;
|
||||
|
||||
localStorage.setItem(unsentKey, JSON.stringify(store));
|
||||
set({ message });
|
||||
}
|
||||
}));
|
||||
|
||||
// const unsentKey = 'chat-unsent';
|
||||
|
||||
// export const useChatStore = create<useChatStoreType>(set => ({
|
||||
// message: retrieve(unsentKey, ''),
|
||||
// setMessage: (message: string) => {
|
||||
// set({ message });
|
||||
// localStorage.setItem(unsentKey, message);
|
||||
// }
|
||||
// }));
|
||||
|
||||
interface ChatPaneProps {
|
||||
/**
|
||||
* A key to uniquely identify a ChatPane instance. Should be either the
|
||||
@ -100,7 +101,7 @@ export function ChatPane(props: ChatPaneProps): ReactElement {
|
||||
} = props;
|
||||
const graphTimesentMap = useGraphTimesent(id);
|
||||
const ourContact = useOurContact();
|
||||
const chatInput = useRef<NakedChatInput>();
|
||||
const chatInput = useRef<{ uploadFiles: (files: FileList | File[]) => void }>();
|
||||
const setMessage = useChatStore(s => s.setMessage);
|
||||
|
||||
const onFileDrag = useCallback(
|
||||
@ -108,29 +109,19 @@ export function ChatPane(props: ChatPaneProps): ReactElement {
|
||||
if (!chatInput.current) {
|
||||
return;
|
||||
}
|
||||
(chatInput.current as NakedChatInput)?.uploadFiles(files);
|
||||
chatInput.current?.uploadFiles(files);
|
||||
},
|
||||
[chatInput]
|
||||
);
|
||||
|
||||
const { bind, dragging } = useFileDrag(onFileDrag);
|
||||
|
||||
const [, setUnsent] = useLocalStorageState<Record<string, string>>(
|
||||
'chat-unsent',
|
||||
{}
|
||||
);
|
||||
|
||||
const appendUnsent = useCallback(
|
||||
(u: string) => setUnsent(s => ({ ...s, [id]: u })),
|
||||
[id]
|
||||
);
|
||||
|
||||
const clearUnsent = useCallback(() => {
|
||||
setUnsent((s) => {
|
||||
if (id in s) {
|
||||
return _.omit(s, id);
|
||||
}
|
||||
return s;
|
||||
useEffect(() => {
|
||||
const messageStore = retrieve(unsentKey, {});
|
||||
useChatStore.setState({
|
||||
id,
|
||||
messageStore,
|
||||
message: messageStore[id] || ''
|
||||
});
|
||||
}, [id]);
|
||||
|
||||
@ -145,8 +136,6 @@ export function ChatPane(props: ChatPaneProps): ReactElement {
|
||||
const onReply = useCallback(
|
||||
(msg: Post) => {
|
||||
const message = props.onReply(msg);
|
||||
console.log(message);
|
||||
// setUnsent(s => ({ ...s, [id]: message }));
|
||||
setMessage(message);
|
||||
},
|
||||
[id, props.onReply]
|
||||
@ -185,9 +174,7 @@ export function ChatPane(props: ChatPaneProps): ReactElement {
|
||||
ref={chatInput}
|
||||
onSubmit={onSubmit}
|
||||
ourContact={(promptShare.length === 0 && ourContact) || undefined}
|
||||
onUnmount={appendUnsent}
|
||||
placeholder="Message..."
|
||||
deleteMessage={clearUnsent}
|
||||
/>
|
||||
)}
|
||||
</Col>
|
||||
|
Loading…
Reference in New Issue
Block a user