From 24559599f3b340a071e96f15b17deb914338d80b Mon Sep 17 00:00:00 2001
From: Paul Frazee <pfrazee@gmail.com>
Date: Thu, 26 Jan 2023 22:08:10 -0600
Subject: [PATCH] Implement web toast

---
 public/index.html               | 19 ---------
 src/App.web.tsx                 |  4 +-
 src/view/com/util/Toast.web.tsx | 75 +++++++++++++++++++++++++++++++++
 3 files changed, 77 insertions(+), 21 deletions(-)
 create mode 100644 src/view/com/util/Toast.web.tsx

diff --git a/public/index.html b/public/index.html
index 50a27bfa..edc9d8e1 100644
--- a/public/index.html
+++ b/public/index.html
@@ -36,25 +36,6 @@
         border-radius: 10px;
         box-shadow: 0 5px 10px #0005;
       }
-
-      /* These styles are for src/view/com/util/Toast */
-      div[data-toast-container] {
-        position: fixed;
-        bottom: 5vh;
-        right: 5vh;
-        width: 350px;
-        padding: 20px;
-        display: flex;
-        flex-direction: row;
-        align-items: center;
-        background: #fff;
-        border-radius: 10px;
-        box-shadow: 0 5px 10px #0005;
-      }
-      div[data-toast-container] > div {
-        font-size: 18px;
-        margin-left: 10px;
-      }
     </style>
   </head>
   <body>
diff --git a/src/App.web.tsx b/src/App.web.tsx
index 67ef680a..4f9fd3e5 100644
--- a/src/App.web.tsx
+++ b/src/App.web.tsx
@@ -3,7 +3,7 @@ import {SafeAreaProvider} from 'react-native-safe-area-context'
 import * as view from './view/index'
 import {RootStoreModel, setupState, RootStoreProvider} from './state'
 import {WebShell} from './view/shell/web'
-// import Toast from 'react-native-root-toast' TODO
+import {ToastContainer} from './view/com/util/Toast.web'
 
 function App() {
   const [rootStore, setRootStore] = useState<RootStoreModel | undefined>(
@@ -26,9 +26,9 @@ function App() {
       <SafeAreaProvider>
         <WebShell />
       </SafeAreaProvider>
+      <ToastContainer />
     </RootStoreProvider>
   )
-  // <Toast.ToastContainer /> TODO
 }
 
 export default App
diff --git a/src/view/com/util/Toast.web.tsx b/src/view/com/util/Toast.web.tsx
new file mode 100644
index 00000000..bce178b4
--- /dev/null
+++ b/src/view/com/util/Toast.web.tsx
@@ -0,0 +1,75 @@
+/*
+ * Note: the dataSet properties are used to leverage custom CSS in public/index.html
+ */
+
+import React, {useState, useEffect} from 'react'
+import {StyleSheet, Text, View} from 'react-native'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+
+const DURATION = 3500
+
+interface ActiveToast {
+  text: string
+}
+type GlobalSetActiveToast = (_activeToast: ActiveToast | undefined) => void
+
+// globals
+// =
+let globalSetActiveToast: GlobalSetActiveToast | undefined
+let toastTimeout: NodeJS.Timeout | undefined
+
+// components
+// =
+type ToastContainerProps = {}
+export const ToastContainer: React.FC<ToastContainerProps> = ({}) => {
+  const [activeToast, setActiveToast] = useState<ActiveToast | undefined>()
+  useEffect(() => {
+    globalSetActiveToast = (t: ActiveToast | undefined) => {
+      setActiveToast(t)
+    }
+  })
+  return (
+    <>
+      {activeToast && (
+        <View style={styles.container}>
+          <FontAwesomeIcon icon="check" size={24} style={styles.icon} />
+          <Text style={styles.text}>{activeToast.text}</Text>
+        </View>
+      )}
+    </>
+  )
+}
+
+// methods
+// =
+export function show(text: string) {
+  if (toastTimeout) {
+    clearTimeout(toastTimeout)
+  }
+  globalSetActiveToast?.({text})
+  toastTimeout = setTimeout(() => {
+    globalSetActiveToast?.(undefined)
+  }, DURATION)
+}
+
+const styles = StyleSheet.create({
+  container: {
+    position: 'absolute',
+    right: 20,
+    bottom: 20,
+    width: 350,
+    padding: 20,
+    flexDirection: 'row',
+    alignItems: 'center',
+    backgroundColor: '#000c',
+    borderRadius: 10,
+  },
+  icon: {
+    color: '#fff',
+  },
+  text: {
+    color: '#fff',
+    fontSize: 18,
+    marginLeft: 10,
+  },
+})