Toast message (#155)
This commit is contained in:
parent
c06c0253bc
commit
7d90ad9ae4
|
@ -12,6 +12,7 @@ import { Members } from "./Members/Members";
|
|||
import { CommunityModal } from "./Modals/CommunityModal";
|
||||
import { EditModal } from "./Modals/EditModal";
|
||||
import { ProfileModal } from "./Modals/ProfileModal";
|
||||
import { ToastMessageList } from "./ToastMessages/ToastMessageList";
|
||||
|
||||
function Modals() {
|
||||
return (
|
||||
|
@ -45,6 +46,7 @@ export function Chat() {
|
|||
{showMembers && !narrow && state === ChatState.ChatBody && <Members />}
|
||||
{state === ChatState.ChatCreation && <ChatCreation />}
|
||||
<Modals />
|
||||
<ToastMessageList />
|
||||
</ChatWrapper>
|
||||
);
|
||||
}
|
||||
|
@ -53,6 +55,7 @@ const ChatWrapper = styled.div`
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const ChannelsWrapper = styled.div`
|
||||
|
|
|
@ -5,6 +5,7 @@ import styled from "styled-components";
|
|||
import { useActivities } from "../../contexts/activityProvider";
|
||||
import { useIdentity } from "../../contexts/identityProvider";
|
||||
import { useModal } from "../../contexts/modalProvider";
|
||||
import { useToasts } from "../../contexts/toastProvider";
|
||||
import { useManageContact } from "../../hooks/useManageContact";
|
||||
import { copy } from "../../utils";
|
||||
import { buttonStyles } from "../Buttons/buttonStyle";
|
||||
|
@ -42,6 +43,8 @@ export const ProfileModal = () => {
|
|||
);
|
||||
|
||||
const { setActivities } = useActivities();
|
||||
const { setToasts } = useToasts();
|
||||
const { setModal } = useModal(ProfileModalName);
|
||||
|
||||
const identity = useIdentity();
|
||||
const isUser = useMemo(
|
||||
|
@ -160,6 +163,7 @@ export const ProfileModal = () => {
|
|||
maxLength={280}
|
||||
onInput={(e) => setRequest(e.currentTarget.value)}
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
</RequestSection>
|
||||
)}
|
||||
|
@ -200,8 +204,16 @@ export const ProfileModal = () => {
|
|||
requestType: "outcome",
|
||||
status: "sent",
|
||||
},
|
||||
]),
|
||||
setToasts((prev) => [
|
||||
...prev,
|
||||
{
|
||||
id: id + request,
|
||||
type: "request",
|
||||
},
|
||||
]),
|
||||
setRequestCreation(false),
|
||||
setModal(false),
|
||||
setRequest("");
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -6,6 +6,7 @@ import { ActivityProvider } from "../contexts/activityProvider";
|
|||
import { FetchMetadataProvider } from "../contexts/fetchMetadataProvider";
|
||||
import { ModalProvider } from "../contexts/modalProvider";
|
||||
import { NarrowProvider } from "../contexts/narrowProvider";
|
||||
import { ToastProvider } from "../contexts/toastProvider";
|
||||
import { Metadata } from "../models/Metadata";
|
||||
import { GlobalStyle } from "../styles/GlobalStyle";
|
||||
import { Theme } from "../styles/themes";
|
||||
|
@ -30,11 +31,13 @@ export function ReactChat({
|
|||
<FetchMetadataProvider fetchMetadata={fetchMetadata}>
|
||||
<ModalProvider>
|
||||
<ActivityProvider>
|
||||
<ToastProvider>
|
||||
<Wrapper ref={ref}>
|
||||
<GlobalStyle />
|
||||
<ChatLoader communityKey={communityKey} />
|
||||
<div id="modal-root" />
|
||||
</Wrapper>
|
||||
</ToastProvider>
|
||||
</ActivityProvider>
|
||||
</ModalProvider>
|
||||
</FetchMetadataProvider>
|
||||
|
|
|
@ -23,8 +23,7 @@ const LoadingBlock = styled.div`
|
|||
padding: 4px 5px 4px 7px;
|
||||
background: ${({ theme }) => theme.bodyBackgroundColor};
|
||||
color: ${({ theme }) => theme.primary};
|
||||
box-shadow: 0px 2px 4px rgba(0, 34, 51, 0.16),
|
||||
0px 4px 12px rgba(0, 34, 51, 0.08);
|
||||
box-shadow: ${({ theme }) => theme.shadow};
|
||||
border-radius: 8px;
|
||||
z-index: 2;
|
||||
`;
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
import React from "react";
|
||||
import styled, { keyframes } from "styled-components";
|
||||
|
||||
import { useToasts } from "../../contexts/toastProvider";
|
||||
import { Toast } from "../../models/Toast";
|
||||
import { CheckSvg } from "../Icons/CheckIcon";
|
||||
import { CrossIcon } from "../Icons/CrossIcon";
|
||||
import { textSmallStyles } from "../Text";
|
||||
|
||||
export function AnimationToastMessage() {
|
||||
return keyframes`
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-100%); }
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0); }
|
||||
`;
|
||||
}
|
||||
|
||||
type ToastMessageProps = {
|
||||
toast: Toast;
|
||||
};
|
||||
|
||||
export function ToastMessage({ toast }: ToastMessageProps) {
|
||||
const { setToasts } = useToasts();
|
||||
|
||||
const closeToast = () => {
|
||||
setToasts((prev) => prev.filter((e) => e != toast));
|
||||
};
|
||||
|
||||
return (
|
||||
<ToastWrapper>
|
||||
<ToastBlock>
|
||||
{toast.type !== "verification" && (
|
||||
<CheckWrapper>
|
||||
<CheckSvg width={20} height={20} className="accept" />
|
||||
</CheckWrapper>
|
||||
)}
|
||||
<ToastText>
|
||||
{toast.type === "request"
|
||||
? "Contact Request Sent"
|
||||
: "Verification Request Sent"}
|
||||
</ToastText>
|
||||
</ToastBlock>
|
||||
<CloseButton onClick={closeToast}>
|
||||
<CrossIcon />
|
||||
</CloseButton>
|
||||
</ToastWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
const ToastWrapper = styled.div`
|
||||
width: 343px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
margin-top: 8px;
|
||||
background: ${({ theme }) => theme.bodyBackgroundColor};
|
||||
box-shadow: ${({ theme }) => theme.shadow};
|
||||
border-radius: 8px;
|
||||
animation: ${AnimationToastMessage} 2s ease;
|
||||
`;
|
||||
|
||||
const ToastBlock = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: ${({ theme }) => theme.primary};
|
||||
`;
|
||||
|
||||
const ToastText = styled.p`
|
||||
font-weight: 500;
|
||||
${textSmallStyles};
|
||||
`;
|
||||
|
||||
const CheckWrapper = styled.div`
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
margin-right: 12px;
|
||||
background: rgba(78, 188, 96, 0.1);
|
||||
`;
|
||||
|
||||
const CloseButton = styled.button`
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
`;
|
|
@ -0,0 +1,31 @@
|
|||
import React, { useMemo } from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { useToasts } from "../../contexts/toastProvider";
|
||||
|
||||
import { ToastMessage } from "./ToastMessage";
|
||||
|
||||
export function ToastMessageList() {
|
||||
const { toasts } = useToasts();
|
||||
|
||||
const shownToasts = useMemo(() => toasts, [toasts, toasts.length]);
|
||||
|
||||
return (
|
||||
<ToastsWrapper>
|
||||
{shownToasts.map((toast) => (
|
||||
<ToastMessage key={toast.id} toast={toast} />
|
||||
))}
|
||||
</ToastsWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
const ToastsWrapper = styled.div`
|
||||
position: absolute;
|
||||
bottom: 56px;
|
||||
right: 16px;
|
||||
width: 343px;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
align-items: center;
|
||||
z-index: 999;
|
||||
`;
|
|
@ -0,0 +1,26 @@
|
|||
import React, { createContext, useContext, useState } from "react";
|
||||
|
||||
import { Toast } from "../models/Toast";
|
||||
|
||||
const ToastContext = createContext<{
|
||||
toasts: Toast[];
|
||||
setToasts: React.Dispatch<React.SetStateAction<Toast[]>>;
|
||||
}>({
|
||||
toasts: [],
|
||||
setToasts: () => undefined,
|
||||
});
|
||||
|
||||
export function useToasts() {
|
||||
return useContext(ToastContext);
|
||||
}
|
||||
|
||||
interface ToastProviderProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function ToastProvider({ children }: ToastProviderProps) {
|
||||
const [toasts, setToasts] = useState<Toast[]>([]);
|
||||
return (
|
||||
<ToastContext.Provider value={{ toasts, setToasts }} children={children} />
|
||||
);
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
export type Toast = {
|
||||
id: string;
|
||||
type: "request" | "incomeRequest" | "verification";
|
||||
};
|
|
@ -24,6 +24,7 @@ export type Theme = {
|
|||
mentionHover: string;
|
||||
mentionBg: string;
|
||||
mentionBgHover: string;
|
||||
shadow: string;
|
||||
};
|
||||
|
||||
export const lightTheme: Theme = {
|
||||
|
@ -52,6 +53,8 @@ export const lightTheme: Theme = {
|
|||
mentionHover: "#BDE7F2",
|
||||
mentionBg: "#E5F8FD",
|
||||
mentionBgHover: "#D4F3FA",
|
||||
shadow:
|
||||
"0px 2px 4px rgba(0, 34, 51, 0.16), 0px 4px 12px rgba(0, 34, 51, 0.08)",
|
||||
};
|
||||
|
||||
export const darkTheme: Theme = {
|
||||
|
@ -80,6 +83,8 @@ export const darkTheme: Theme = {
|
|||
mentionHover: "#004E60",
|
||||
mentionBg: "#004050",
|
||||
mentionBgHover: "#002D39",
|
||||
shadow:
|
||||
"0px 2px 4px rgba(0, 34, 51, 0.16), 0px 4px 12px rgba(0, 34, 51, 0.08)",
|
||||
};
|
||||
|
||||
export default { lightTheme, darkTheme };
|
||||
|
|
Loading…
Reference in New Issue