Add Chat Settings
This commit is contained in:
parent
d2d64e4ec4
commit
396a1f1f46
5 changed files with 145 additions and 11 deletions
|
@ -11,13 +11,16 @@ type WindowState = 'open' | 'minimized';
|
|||
const ChatContext = createContext<any>({
|
||||
chat: null,
|
||||
isOpen: false,
|
||||
isEditing: false,
|
||||
});
|
||||
|
||||
const ChatProvider: React.FC = ({ children }) => {
|
||||
const dispatch = useDispatch();
|
||||
const settings = useSettings();
|
||||
|
||||
const [chat, setChat] = useState<IChat | null>();
|
||||
const [chat, setChat] = useState<IChat | null>(null);
|
||||
const [isEditing, setEditing] = useState<boolean>(false);
|
||||
|
||||
const mainWindowState = settings.getIn(['chats', 'mainWindow']) as WindowState;
|
||||
|
||||
const isOpen = mainWindowState === 'open';
|
||||
|
@ -25,14 +28,18 @@ const ChatProvider: React.FC = ({ children }) => {
|
|||
const toggleChatPane = () => dispatch(toggleMainWindow());
|
||||
|
||||
return (
|
||||
<ChatContext.Provider value={{ chat, setChat, isOpen, toggleChatPane }}>{children}</ChatContext.Provider>
|
||||
<ChatContext.Provider value={{ chat, setChat, isOpen, isEditing, setEditing, toggleChatPane }}>
|
||||
{children}
|
||||
</ChatContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
interface IChatContext {
|
||||
chat: IChat | null
|
||||
isOpen: boolean
|
||||
isEditing: boolean
|
||||
setChat: React.Dispatch<React.SetStateAction<IChat | null>>
|
||||
setEditing: React.Dispatch<React.SetStateAction<boolean>>
|
||||
toggleChatPane(): void
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ const ChatPane = () => {
|
|||
<Text weight='semibold' truncate>{account.display_name}</Text>
|
||||
{account.verified && <VerificationBadge />}
|
||||
</div>
|
||||
<Text theme='muted' truncate>{account.acct}</Text>
|
||||
<Text theme='muted' truncate>@{account.acct}</Text>
|
||||
</Stack>
|
||||
</HStack>
|
||||
</button>
|
||||
|
@ -128,10 +128,10 @@ const ChatPane = () => {
|
|||
|
||||
<Stack alignItems='start'>
|
||||
<div className='flex items-center space-x-1 flex-grow'>
|
||||
<Text weight='semibold' truncate>{chat.account?.display_name}</Text>
|
||||
<Text weight='bold' size='sm' truncate>{chat.account?.display_name}</Text>
|
||||
{chat.account?.verified && <VerificationBadge />}
|
||||
</div>
|
||||
<Text theme='muted' truncate>{chat.account?.acct}</Text>
|
||||
<Text size='sm' weight='medium' theme='muted' truncate>@{chat.account?.acct}</Text>
|
||||
</Stack>
|
||||
</HStack>
|
||||
</button>
|
||||
|
|
119
app/soapbox/features/chats/components/chat-settings.tsx
Normal file
119
app/soapbox/features/chats/components/chat-settings.tsx
Normal file
|
@ -0,0 +1,119 @@
|
|||
import React from 'react';
|
||||
|
||||
import { blockAccount } from 'soapbox/actions/accounts';
|
||||
import { openModal } from 'soapbox/actions/modals';
|
||||
import { initReport } from 'soapbox/actions/reports';
|
||||
import List, { ListItem } from 'soapbox/components/list';
|
||||
import { Avatar, Divider, HStack, Icon, Stack, Text, Toggle } from 'soapbox/components/ui';
|
||||
import { useChatContext } from 'soapbox/contexts/chat-context';
|
||||
import { useAppDispatch } from 'soapbox/hooks';
|
||||
import { useChat } from 'soapbox/queries/chats';
|
||||
|
||||
import ChatPaneHeader from './chat-pane-header';
|
||||
|
||||
const ChatSettings = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { chat, setEditing, toggleChatPane } = useChatContext();
|
||||
const { deleteChat } = useChat(chat?.id as string);
|
||||
|
||||
const closeSettings = () => setEditing(false);
|
||||
|
||||
const minimizeChatPane = () => {
|
||||
closeSettings();
|
||||
toggleChatPane();
|
||||
};
|
||||
|
||||
const handleBlockUser = () => {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
heading: `Block @${chat?.account.acct}`,
|
||||
message: 'Blocking will prevent this profile from direct messaging you and viewing your content. You can unblock later.',
|
||||
confirm: 'Block',
|
||||
confirmationTheme: 'primary',
|
||||
onConfirm: () => dispatch(blockAccount(chat?.account.id)),
|
||||
}));
|
||||
};
|
||||
|
||||
const handleLeaveChat = () => {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
heading: 'Leave Chat',
|
||||
message: 'Are you sure you want to leave this chat? This conversation will be removed from your inbox.',
|
||||
confirm: 'Leave Chat',
|
||||
confirmationTheme: 'primary',
|
||||
onConfirm: () => {
|
||||
deleteChat.mutate();
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
const handleReportChat = () => {
|
||||
dispatch(initReport(chat?.account));
|
||||
};
|
||||
|
||||
if (!chat) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ChatPaneHeader
|
||||
isOpen
|
||||
isToggleable={false}
|
||||
onToggle={minimizeChatPane}
|
||||
title={
|
||||
<HStack alignItems='center' space={2}>
|
||||
<button onClick={closeSettings}>
|
||||
<Icon
|
||||
src={require('@tabler/icons/arrow-left.svg')}
|
||||
className='h-6 w-6 text-gray-600 dark:text-gray-400'
|
||||
/>
|
||||
</button>
|
||||
|
||||
<Text weight='semibold'>
|
||||
Chat Details
|
||||
</Text>
|
||||
</HStack>
|
||||
}
|
||||
/>
|
||||
|
||||
<Stack space={4} className='w-5/6 mx-auto'>
|
||||
<Stack alignItems='center' space={2}>
|
||||
<Avatar src={chat.account.avatar_static} size={75} />
|
||||
<Stack>
|
||||
<Text size='lg' weight='semibold' align='center'>{chat.account.display_name}</Text>
|
||||
<Text theme='primary' align='center'>@{chat.account.acct}</Text>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Divider />
|
||||
|
||||
<List>
|
||||
<ListItem label='Snooze notifications'>
|
||||
<Toggle />
|
||||
</ListItem>
|
||||
</List>
|
||||
|
||||
<Divider />
|
||||
|
||||
<Stack space={5}>
|
||||
<button onClick={handleBlockUser} className='w-full flex items-center space-x-2 font-bold text-sm text-gray-700'>
|
||||
<Icon src={require('@tabler/icons/ban.svg')} className='w-5 h-5 text-gray-600' />
|
||||
<span>Block @{chat.account.acct}</span>
|
||||
</button>
|
||||
|
||||
<button onClick={handleReportChat} className='w-full flex items-center space-x-2 font-bold text-sm text-gray-700'>
|
||||
<Icon src={require('@tabler/icons/flag.svg')} className='w-5 h-5 text-gray-600' />
|
||||
<span>Report @{chat.account.acct}</span>
|
||||
</button>
|
||||
|
||||
<button onClick={handleLeaveChat} className='w-full flex items-center space-x-2 font-bold text-sm text-danger-600'>
|
||||
<Icon src={require('@tabler/icons/logout.svg')} className='w-5 h-5 text-danger-600' />
|
||||
<span>Leave chat</span>
|
||||
</button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatSettings;
|
|
@ -6,21 +6,29 @@ import { useChatContext } from 'soapbox/contexts/chat-context';
|
|||
|
||||
import ChatBox from './chat-box';
|
||||
import ChatPaneHeader from './chat-pane-header';
|
||||
import ChatSettings from './chat-settings';
|
||||
|
||||
/** Floating desktop chat window. */
|
||||
const ChatWindow = () => {
|
||||
const { chat, setChat, isOpen, toggleChatPane } = useChatContext();
|
||||
const { chat, setChat, isOpen, isEditing, setEditing, toggleChatPane } = useChatContext();
|
||||
|
||||
const inputRef = useRef<HTMLTextAreaElement>();
|
||||
|
||||
const closeChat = () => setChat(null);
|
||||
|
||||
const openAndFocusChat = () => {
|
||||
toggleChatPane();
|
||||
inputRef.current?.focus();
|
||||
};
|
||||
|
||||
const openChatSettings = () => setEditing(true);
|
||||
|
||||
if (!chat) return null;
|
||||
|
||||
if (isEditing) {
|
||||
return <ChatSettings />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ChatPaneHeader
|
||||
|
@ -42,16 +50,16 @@ const ChatWindow = () => {
|
|||
|
||||
<Stack alignItems='start'>
|
||||
<div className='flex items-center space-x-1 flex-grow'>
|
||||
<Text weight='semibold' truncate>{chat.account.display_name}</Text>
|
||||
<Text size='sm' weight='bold' truncate>{chat.account.display_name}</Text>
|
||||
{chat.account.verified && <VerificationBadge />}
|
||||
</div>
|
||||
<Text theme='muted' truncate>{chat.account.acct}</Text>
|
||||
<Text size='sm' weight='medium' theme='primary' truncate>@{chat.account.acct}</Text>
|
||||
</Stack>
|
||||
</HStack>
|
||||
</HStack>
|
||||
}
|
||||
secondaryAction={isOpen ? undefined : openAndFocusChat}
|
||||
secondaryActionIcon={isOpen ? undefined : require('@tabler/icons/edit.svg')}
|
||||
secondaryAction={isOpen ? openChatSettings : openAndFocusChat}
|
||||
secondaryActionIcon={isOpen ? require('@tabler/icons/info-circle.svg') : require('@tabler/icons/edit.svg')}
|
||||
isToggleable={!isOpen}
|
||||
isOpen={isOpen}
|
||||
onToggle={toggleChatPane}
|
||||
|
|
|
@ -18,7 +18,7 @@ const Pane: React.FC<IPane> = ({ isOpen = false, index, children, main = false }
|
|||
|
||||
return (
|
||||
<div
|
||||
className={classNames('flex flex-col shadow-3xl bg-white dark:bg-gray-900 rounded-t-lg fixed bottom-0 right-1 w-96 z-[1000]', {
|
||||
className={classNames('flex flex-col shadow-3xl bg-white dark:bg-gray-900 rounded-t-lg fixed bottom-0 right-1 w-96 z-[99]', {
|
||||
'h-[550px] max-h-[100vh]': isOpen,
|
||||
'h-16': !isOpen,
|
||||
})}
|
||||
|
|
Loading…
Reference in a new issue