Skip to content

Commit

Permalink
feat: migrating redux state to redux toolkit and typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
raaymax committed Apr 11, 2024
1 parent 0149a48 commit 1f30981
Show file tree
Hide file tree
Showing 73 changed files with 710 additions and 378 deletions.
3 changes: 2 additions & 1 deletion packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
"dependencies": {
"@quack/config": "workspace:*",
"@quack/rpc": "workspace:*",
"@reduxjs/toolkit": "2.2.3",
"fuse.js": "7.0.0",
"prop-types": "15.8.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-redux": "9.0.4",
"react-redux": "9.1.0",
"redux": "5.0.0",
"socket.io-client": "4.7.2",
"styled-components": "6.1.1",
Expand Down
7 changes: 3 additions & 4 deletions packages/app/src/js/components/Secured.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { useEffect } from 'react';
import { Provider } from 'react-redux';
import { ThemeProvider } from 'styled-components';
import '../setup';
import { client } from '../core';
import { store } from '../store';
import StoreProvider from '../store/components/provider';
import { Workspace } from './pages/Workspace';
import { useUser } from './contexts/useUser';

Expand Down Expand Up @@ -45,11 +44,11 @@ const Secured = () => {
}, [user]);

return (
<Provider store={store}>
<StoreProvider>
<ThemeProvider theme={theme}>
<Workspace />
</ThemeProvider>
</Provider>
</StoreProvider>
);
};

Expand Down
6 changes: 3 additions & 3 deletions packages/app/src/js/components/atoms/StatusLine.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useSelector } from 'react-redux';
import { useTyping } from '../../hooks';
import { useTyping} from '../../hooks';
import { useSelector } from '../../store';

export const StatusLine = () => {
const info = useSelector((state: any) => state.info);
const info = useSelector((state) => state.info);
const typing = useTyping(); // FIXME: status line should work in context

const names = (typing || []).map((u) => u.name).join(', ');
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/js/components/atoms/UserCircle.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useSelector } from 'react-redux';
import styled from 'styled-components';
import { cn, ClassNames } from '../../utils';
import { useSelector } from '../../store';

const Image = styled.img`
display: inline-block;
Expand All @@ -17,7 +17,7 @@ type UserCircleProps = {

export const UserCircle = ({ userId, className }: UserCircleProps) => {
// FIXME: state type
const user = useSelector((state: any) => state.users[userId]);
const user = useSelector((state) => state.users[userId]);
if (!user) return null;
return (
<Image className={cn(className)} src={user.avatarUrl} alt={user.name} />
Expand Down
8 changes: 4 additions & 4 deletions packages/app/src/js/components/contexts/input.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {
useRef, useState, useCallback, useEffect, createContext, MutableRefObject,
} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch, useSelector } from '../../store';
import { useStream } from './useStream';
import * as messageService from '../../services/messages';
import { uploadMany } from '../../services/file';
Expand Down Expand Up @@ -52,14 +52,14 @@ type InputContextProps = {

export const InputProvider = (args: InputContextProps) => {
const { children, mode = 'default', messageId = null } = args;
const dispatch: any = useDispatch();
const dispatch = useDispatch();
const [stream] = useStream();
const [currentText, setCurrentText] = useState('');
const [scope, setScope] = useState<string>('');
const [scopeContainer, setScopeContainer] = useState<HTMLElement>();
//FIXME: files as any
const files = useSelector((state: any) => state.files);
const filesAreReady = !files || files.every((f: any) => f.status === 'ok');
const files = useSelector((state) => state.files);
const filesAreReady = !files || files.every((f) => f.status === 'ok');
const message = useMessage(messageId);

const input = useRef<HTMLDivElement | null>(null);
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/contexts/useMessages.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
useMemo, useEffect, useState
} from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useSelector, useDispatch } from '../../store';
import { loadMessages, loadNext, loadPrevious } from '../../services/messages';
import { Message } from '../../types';
import { useStream } from './useStream';
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/molecules/Attachments.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch, useSelector } from '../../store';
import styled from 'styled-components';
import { abort } from '../../services/file';
import { useStream } from '../contexts/useStream';
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/molecules/ChannelCreate.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState, useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { useDispatch } from '../../store';
import styled from 'styled-components';

const NewChannelContainer = styled.div`
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/molecules/ChannelLink.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch, useSelector } from '../../store';
import styled from 'styled-components';
import { Icon } from '../atoms/Icon';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useSelector } from 'react-redux';
import { useSelector } from '../../store';
import {
useCallback, useEffect, useState, useMemo,
} from 'react';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useSelector } from 'react-redux';
import { useSelector } from '../../store';
import { Loader } from '../atoms/Loader';

export function LoadingIndicator() {
Expand Down
8 changes: 4 additions & 4 deletions packages/app/src/js/components/molecules/MessageToolbar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState, useCallback, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch, useSelector } from '../../store';
import { removeMessage } from '../../services/messages';
import { useHovered } from '../contexts/useHovered';
import { useStream } from '../contexts/useStream';
Expand Down Expand Up @@ -71,15 +71,15 @@ export const MessageToolbar = () => {
<ButtonWithEmoji
key={emoji}
emoji={emoji}
onClick={() => dispatch.methods.messages.addReaction(id, emoji)} />
onClick={() => dispatch.methods.messages.addReaction({id, text: emoji})} />
);
const deleteButton = () => <ButtonWithIcon key='del' icon="delete" onClick={() => setView('delete')} />;
const confirmDelete = () => <ButtonWithIcon key='confirm_del' icon="check:danger" onClick={onDelete} />;
const cancelButton = () => <ButtonWithIcon key='cancel' icon="circle-xmark" onClick={() => setView(null)} />;
const editButton = () => <ButtonWithIcon key='edit' icon="edit" onClick={() => dispatch.actions.messages.toggleEdit(id)} />;
const openReactions = () => <ButtonWithIcon key='reactions' icon="icons" onClick={() => setView('reactions')} />;
const pinButton = () => <ButtonWithIcon key='pin' icon="thumbtack" onClick={() => dispatch.methods.pins.pin(id, channelId)} />;
const unpinButton = () => <ButtonWithIcon key='unpin' icon="thumbtack" onClick={() => dispatch.methods.pins.unpin(id, channelId)} />;
const pinButton = () => <ButtonWithIcon key='pin' icon="thumbtack" onClick={() => dispatch.methods.pins.pin({id, channelId})} />;
const unpinButton = () => <ButtonWithIcon key='unpin' icon="thumbtack" onClick={() => dispatch.methods.pins.unpin({id, channelId})} />;
const replyButton = () => <ButtonWithIcon key='reply' icon="reply" onClick={() => dispatch.actions.stream.open({ id: 'side', value: { type: 'live', channelId, parentId: id } })} />;

return (
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/molecules/NavChannel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch, useSelector } from '../../store';
import styled from 'styled-components';
import { Badge } from '../atoms/Badge';
import { TextWithIcon } from './TextWithIcon';
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/molecules/NavChannels.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {useState} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch, useSelector } from '../../store';
import styled from 'styled-components';
import { ChannelCreate } from './ChannelCreate';
import { Channel } from './NavChannel';
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/molecules/NavUser.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useSelector } from 'react-redux';
import { useSelector } from '../../store';
import { NavButton } from './NavButton';
import { ClassNames, cn } from '../../utils';

Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/molecules/NavUsers.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch, useSelector } from '../../store';
import styled from 'styled-components';
import { NavUserButton } from './NavUser';
import { useBadges, useUserChannels } from '../../hooks';
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/js/components/molecules/Reactions.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useDispatch } from 'react-redux';
import { useDispatch } from '../../store';
import { useMessageData } from '../contexts/useMessageData';
import { Emoji } from './Emoji';
import { Tag } from '../atoms/Tag';
Expand All @@ -12,7 +12,7 @@ export const Reactions = () => {
return (
<div>
{Object.entries(reactionMap).map(([key, count]) => (
<Tag key={key} onClick={() => dispatch.methods.messages.addReaction(id, key)}>
<Tag key={key} onClick={() => dispatch.methods.messages.addReaction({id, text: key})}>
{count > 1 ? `${count} ` : ''}
<Emoji shortname={key} />
</Tag>
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/molecules/ThreadLink.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import styled from 'styled-components';
import { useDispatch } from 'react-redux';
import { useDispatch } from '../../store';

const Link = styled.span`
color: ${(props) => props.theme.linkColor};
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/molecules/UserMention.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useSelector, useDispatch } from 'react-redux';
import { useSelector, useDispatch } from '../../store';
import styled from 'styled-components';
import { gotoDirectChannel } from '../../services/channels';

Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/organisms/Conversation.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useCallback} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch, useSelector } from '../../store';
import { MessageList } from './MessageListScroller';
import { uploadMany } from '../../services/file';
import { Input } from '../organisms/Input';
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/organisms/EmojiSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState, useEffect} from 'react';
import { useSelector } from 'react-redux';
import { useSelector } from '../../store';
import { Tooltip } from '../atoms/Tooltip';
import { SearchBox } from '../atoms/SearchBox';
import { useEmojiFuse } from '../../hooks';
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/organisms/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, useState, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { useDispatch } from '../../store';
import styled from 'styled-components';

import { EmojiDescriptor } from '../../types';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styled from 'styled-components';
import { Conversation } from './Conversation';
import { useDispatch } from 'react-redux';
import { useDispatch } from '../../store';
import { Channel } from '../molecules/NavChannel';
import { init } from '../../services/init';
import { useStream } from '../contexts/useStream';
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/organisms/Message.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { useDispatch } from '../../store';
import styled from 'styled-components';

import { resend } from '../../services/messages';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styled from 'styled-components';
import { Conversation } from './Conversation';
import { useDispatch } from 'react-redux';
import { useDispatch } from '../../store';
import { Channel } from '../molecules/NavChannel';
import { useStream } from '../contexts/useStream';
import { useMessage } from '../../hooks';
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/organisms/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { NavUsers } from '../molecules/NavUsers';
import { NavButton } from '../molecules/NavButton';
import plugins from '../../core/plugins';
import { logout } from '../../services/session';
import { useDispatch } from 'react-redux';
import { useDispatch } from '../../store';


export const SideMenu = styled.div`
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/pages/Pins.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import styled from 'styled-components';
import { Channel } from '../molecules/NavChannel';
import { useStream } from '../contexts/useStream';
import { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch, useSelector } from '../../store';
import { HoverProvider } from '../contexts/hover';
import { MessageList } from '../organisms/MessageListScroller'
import { Message as MessageType } from '../../types';
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/js/components/pages/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import styled from 'styled-components';
import { useCallback, useState } from 'react';
import { useStream } from '../contexts/useStream';
import { HoverProvider } from '../contexts/hover';
import { useSelector, useDispatch } from 'react-redux';
import { useSelector, useDispatch } from '../../store';
import { formatTime, formatDate } from '../../utils';

import { SearchBox } from '../atoms/SearchBox';
Expand Down Expand Up @@ -108,7 +108,7 @@ export const Header = () => {
const [value, setValue] = useState('');

const submit = useCallback(async () => {
dispatch.methods.search.find(stream.channelId, value);
dispatch.methods.search.find({channelId: stream.channelId, text: value});
}, [dispatch, stream, value]);

const onKeyDown= useCallback(async (e: React.KeyboardEvent) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/js/components/pages/Workspace.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch, useSelector } from '../../store';

import { MainConversation } from '../organisms/MainConversaion';
import { SideConversation } from '../organisms/SideConversation';
Expand Down
File renamed without changes.
8 changes: 4 additions & 4 deletions packages/app/src/js/hooks/useEmoji.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useMemo, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useDispatch, useSelector } from '../store';

type Emoji = {
shortname: string;
Expand All @@ -10,16 +10,16 @@ type Emoji = {

export const useEmoji = (shortname: string): Emoji => {
const dispatch = useDispatch();
const emojis = useSelector((state: any) => state.emojis);
const emojis = useSelector((state) => state.emojis);
const emoji = useMemo(
() => emojis.data.find((emoji: Emoji) => emoji.shortname === shortname),
[emojis, shortname],
);
useEffect(() => {
if (!emoji && emojis.ready) {
(dispatch as any).methods.emojis.find(shortname);
dispatch.methods.emojis.find(shortname);
}
}, [dispatch, emoji, shortname, emojis]);

return emoji;
return emoji ?? { shortname, empty: true};
};
4 changes: 2 additions & 2 deletions packages/app/src/js/services/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ const tempId = createCounter(`file:${(Math.random() + 1).toString(36)}`);

const FILES_URL = `${API_URL}/files`;

export const uploadMany = (streamId, files) => async (dispatch) => {
export const uploadMany = (streamId, files) => ({type: 'async', handler: async (dispatch) => {
for (let i = 0, file; i < files.length; i++) {
file = files.item(i);
dispatch(upload(streamId, file));
}
};
}});

export const upload = (streamId, file) => async (dispatch) => {
const local = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { client } from '../core';
import { createCounter } from '../utils';
import { createAsyncAction } from '../store';

const tempId = createCounter(`temp:${(Math.random() + 1).toString(36)}`);

const loading = (dispatch) => {
dispatch.actions.messages.loading();
const timer = setTimeout(() => dispatch.actions.messages.loadingDone(), 1000);
const loading = createAsyncAction(async (dispatch) => {
dispatch.actions.messages.loading({});
const timer = setTimeout(() => dispatch.actions.messages.loadingDone({}), 1000);
return () => {
dispatch.actions.messages.loadingDone();
dispatch.actions.messages.loadingDone({});
clearTimeout(timer);
};
};
});

const getStreamMessages = (stream, messages) => messages
.filter((m) => m.channelId === stream.channelId
Expand Down Expand Up @@ -119,9 +120,9 @@ export const sendFromDom = (stream, dom) => async (dispatch, getState) => {
}
};

export const send = (stream, msg) => (dispatch) => dispatch(msg.type === 'command:execute' ? sendCommand(stream, msg) : sendMessage(msg));
export const send = (stream, msg) => createAsyncAction((dispatch) => dispatch(msg.type === 'command:execute' ? sendCommand(stream, msg) : sendMessage(msg)));

export const sendShareMessage = (data) => async (dispatch, getState) => {
export const sendShareMessage = (data) => createAsyncAction(async (dispatch, getState) => {
const { channelId, parentId } = getState().stream.main;
const info = { links: [] };
const msg = build({
Expand All @@ -147,7 +148,7 @@ export const sendShareMessage = (data) => async (dispatch, getState) => {
},
});
}
};
});

const buildShareMessage = (data, info) => {
const lines = [];
Expand Down
Loading

0 comments on commit 1f30981

Please sign in to comment.