From 7d90ad9ae4f0606cdec396681426c6b0e1a54411 Mon Sep 17 00:00:00 2001
From: Maria Rushkova <66270386+mrushkova@users.noreply.github.com>
Date: Mon, 13 Dec 2021 18:09:26 +0100
Subject: [PATCH] Toast message (#155)
---
packages/react-chat/src/components/Chat.tsx | 3 +
.../src/components/Modals/ProfileModal.tsx | 12 +++
.../react-chat/src/components/ReactChat.tsx | 13 ++-
.../src/components/Skeleton/Loading.tsx | 3 +-
.../components/ToastMessages/ToastMessage.tsx | 91 +++++++++++++++++++
.../ToastMessages/ToastMessageList.tsx | 31 +++++++
.../react-chat/src/contexts/toastProvider.tsx | 26 ++++++
packages/react-chat/src/models/Toast.ts | 4 +
packages/react-chat/src/styles/themes.ts | 5 +
9 files changed, 181 insertions(+), 7 deletions(-)
create mode 100644 packages/react-chat/src/components/ToastMessages/ToastMessage.tsx
create mode 100644 packages/react-chat/src/components/ToastMessages/ToastMessageList.tsx
create mode 100644 packages/react-chat/src/contexts/toastProvider.tsx
create mode 100644 packages/react-chat/src/models/Toast.ts
diff --git a/packages/react-chat/src/components/Chat.tsx b/packages/react-chat/src/components/Chat.tsx
index 99149af..64bad96 100644
--- a/packages/react-chat/src/components/Chat.tsx
+++ b/packages/react-chat/src/components/Chat.tsx
@@ -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 && }
{state === ChatState.ChatCreation && }
+
);
}
@@ -53,6 +55,7 @@ const ChatWrapper = styled.div`
width: 100%;
height: 100%;
display: flex;
+ position: relative;
`;
const ChannelsWrapper = styled.div`
diff --git a/packages/react-chat/src/components/Modals/ProfileModal.tsx b/packages/react-chat/src/components/Modals/ProfileModal.tsx
index 153c30f..2d85e12 100644
--- a/packages/react-chat/src/components/Modals/ProfileModal.tsx
+++ b/packages/react-chat/src/components/Modals/ProfileModal.tsx
@@ -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
/>
)}
@@ -201,7 +205,15 @@ export const ProfileModal = () => {
status: "sent",
},
]),
+ setToasts((prev) => [
+ ...prev,
+ {
+ id: id + request,
+ type: "request",
+ },
+ ]),
setRequestCreation(false),
+ setModal(false),
setRequest("");
}}
>
diff --git a/packages/react-chat/src/components/ReactChat.tsx b/packages/react-chat/src/components/ReactChat.tsx
index c1bdaa9..4af8590 100644
--- a/packages/react-chat/src/components/ReactChat.tsx
+++ b/packages/react-chat/src/components/ReactChat.tsx
@@ -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({
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/packages/react-chat/src/components/Skeleton/Loading.tsx b/packages/react-chat/src/components/Skeleton/Loading.tsx
index a742036..c15a220 100644
--- a/packages/react-chat/src/components/Skeleton/Loading.tsx
+++ b/packages/react-chat/src/components/Skeleton/Loading.tsx
@@ -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;
`;
diff --git a/packages/react-chat/src/components/ToastMessages/ToastMessage.tsx b/packages/react-chat/src/components/ToastMessages/ToastMessage.tsx
new file mode 100644
index 0000000..71b93de
--- /dev/null
+++ b/packages/react-chat/src/components/ToastMessages/ToastMessage.tsx
@@ -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 (
+
+
+ {toast.type !== "verification" && (
+
+
+
+ )}
+
+ {toast.type === "request"
+ ? "Contact Request Sent"
+ : "Verification Request Sent"}
+
+
+
+
+
+
+ );
+}
+
+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;
+`;
diff --git a/packages/react-chat/src/components/ToastMessages/ToastMessageList.tsx b/packages/react-chat/src/components/ToastMessages/ToastMessageList.tsx
new file mode 100644
index 0000000..557b8e2
--- /dev/null
+++ b/packages/react-chat/src/components/ToastMessages/ToastMessageList.tsx
@@ -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 (
+
+ {shownToasts.map((toast) => (
+
+ ))}
+
+ );
+}
+
+const ToastsWrapper = styled.div`
+ position: absolute;
+ bottom: 56px;
+ right: 16px;
+ width: 343px;
+ display: flex;
+ flex-direction: column-reverse;
+ align-items: center;
+ z-index: 999;
+`;
diff --git a/packages/react-chat/src/contexts/toastProvider.tsx b/packages/react-chat/src/contexts/toastProvider.tsx
new file mode 100644
index 0000000..06eeb62
--- /dev/null
+++ b/packages/react-chat/src/contexts/toastProvider.tsx
@@ -0,0 +1,26 @@
+import React, { createContext, useContext, useState } from "react";
+
+import { Toast } from "../models/Toast";
+
+const ToastContext = createContext<{
+ toasts: Toast[];
+ setToasts: React.Dispatch>;
+}>({
+ toasts: [],
+ setToasts: () => undefined,
+});
+
+export function useToasts() {
+ return useContext(ToastContext);
+}
+
+interface ToastProviderProps {
+ children: React.ReactNode;
+}
+
+export function ToastProvider({ children }: ToastProviderProps) {
+ const [toasts, setToasts] = useState([]);
+ return (
+
+ );
+}
diff --git a/packages/react-chat/src/models/Toast.ts b/packages/react-chat/src/models/Toast.ts
new file mode 100644
index 0000000..2d3622c
--- /dev/null
+++ b/packages/react-chat/src/models/Toast.ts
@@ -0,0 +1,4 @@
+export type Toast = {
+ id: string;
+ type: "request" | "incomeRequest" | "verification";
+};
diff --git a/packages/react-chat/src/styles/themes.ts b/packages/react-chat/src/styles/themes.ts
index 0122db9..cdc2d9e 100644
--- a/packages/react-chat/src/styles/themes.ts
+++ b/packages/react-chat/src/styles/themes.ts
@@ -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 };