diff --git a/_frontend/src/components/Sidebar.jsx b/_frontend/src/components/Sidebar.jsx
index 52cb932..d7ccd72 100644
--- a/_frontend/src/components/Sidebar.jsx
+++ b/_frontend/src/components/Sidebar.jsx
@@ -1,6 +1,8 @@
-import { useState } from 'preact/hooks'
+import { useEffect, useState } from 'preact/hooks'
import { Icon } from './Icon.jsx'
import { useStore } from '../context.jsx'
+import { useRemoteState } from '../util.jsx'
+import { useToasts } from './Toasts.jsx'
const SidebarDropdownItem = ({ icon, label, children }) => {
const [collapsed, setCollapsed] = useState(false)
@@ -28,7 +30,16 @@ const SidebarDropdownItem = ({ icon, label, children }) => {
}
export const Sidebar = () => {
- const { sidebarVisibile, buckets, user } = useStore()
+ const { sidebarVisibile, user } = useStore()
+
+ const [showToast] = useToasts()
+
+ const [buckets, err] = useRemoteState('/api/buckets', [])
+ useEffect(() => {
+ if (err) {
+ showToast(`Errore "${err}"`)
+ }
+ }, [err])
return (
user === 'admin' && (
@@ -77,7 +88,7 @@ export const Sidebar = () => {
{buckets.map(bucket => (
-
+
)
diff --git a/_frontend/src/components/Toasts.jsx b/_frontend/src/components/Toasts.jsx
index 3dd895b..1d14b13 100644
--- a/_frontend/src/components/Toasts.jsx
+++ b/_frontend/src/components/Toasts.jsx
@@ -1,35 +1,57 @@
-import { useStore } from '../context.jsx'
+import { createContext } from 'preact'
+import { useContext, useState } from 'preact/hooks'
+import { Icon } from './Icon.jsx'
let globalToastId = 0
-export const Toasts = () => {
- const { toasts } = useStore()
+const ToastContext = createContext([])
+
+export const ToastProvider = ({ children }) => {
+ const [toasts, setToasts] = useState([])
+
+ const removeToast = uid => {
+ setToasts(toasts => toasts.filter(t => t.uid !== uid))
+ }
return (
-
- {toasts.map(({ i, removed, message }) => (
-
- {message}
-
- ))}
-
+
+ {children}
+
+ {toasts.map(({ uid, removed, message }) => (
+
+
{message}
+
removeToast(uid)}>
+
+
+
+ ))}
+
+
)
}
-const cleanToasts = setToasts => {
- setToasts(ts => ts.filter((t, i) => !t.removed))
-}
+export const useToasts = () => {
+ const { setToasts } = useContext(ToastContext)
+
+ const showToast = (message, { duration } = {}) => {
+ duration ??= 3000
+
+ const toast = { uid: globalToastId++, removed: false, message }
+
+ setTimeout(() => {
+ setToasts(toasts => toasts.map(t => (t === toast ? { ...t, removed: true } : t)))
+ }, duration)
-export const showToast = (_toasts, setToasts) => message => {
- const toast = { i: globalToastId++, removed: false, message }
+ setTimeout(() => {
+ setToasts(toasts => toasts.filter(t => !t.removed))
+ }, duration + 1000)
- setTimeout(() => {
- setToasts(ts => ts.map(t => (t === toast ? { ...t, removed: true } : t)))
- }, 3000)
+ setToasts(ts => [...ts.slice(-5), toast])
+ }
- setTimeout(() => {
- cleanToasts(setToasts)
- }, 4000)
+ const clearToasts = () => {
+ setToasts([])
+ }
- setToasts(ts => [...ts.slice(-5), toast])
+ return [showToast, clearToasts]
}
diff --git a/_frontend/src/main.jsx b/_frontend/src/main.jsx
index 03a5f97..ea78197 100644
--- a/_frontend/src/main.jsx
+++ b/_frontend/src/main.jsx
@@ -7,9 +7,9 @@ import { Login } from './pages/Login.jsx'
import { Store, useStore } from './context.jsx'
import { changeCase, useRouter, useUser } from './util.jsx'
import { Dashboard } from './pages/Dashboard.jsx'
-import { showToast, Toasts } from './components/Toasts.jsx'
import { Sidebar } from './components/Sidebar.jsx'
import { MainContent } from './components/MainContent.jsx'
+import { ToastProvider } from './components/Toasts.jsx'
const App = () => {
const [id, route, routeParams] = useRouter({
@@ -52,27 +52,14 @@ const App = () => {
}
})
- const [toasts, setToasts] = useState([])
const [sidebarVisibile, setSidebarVisible] = useState(true)
- const [buckets, setBuckets] = useState([])
- useEffect(() => {
- fetch('/api/buckets')
- .then(res => res.json())
- .then(value => setBuckets(value))
- }, [])
-
const context = {
// Auth
user,
// Sidebar
sidebarVisibile,
setSidebarVisible,
- buckets,
- // Toasts
- toasts,
- setToasts,
- showToast: showToast(toasts, setToasts),
// Routing
route: {
...route,
@@ -82,11 +69,12 @@ const App = () => {
}
return (
-
-
-
-
-
+
+
+ {user === 'admin' && }
+
+
+
)
}
diff --git a/_frontend/src/pages/ApiKeys.jsx b/_frontend/src/pages/ApiKeys.jsx
index 2b97b3e..994c26b 100644
--- a/_frontend/src/pages/ApiKeys.jsx
+++ b/_frontend/src/pages/ApiKeys.jsx
@@ -1,9 +1,10 @@
import { useEffect, useState } from 'preact/hooks'
import { Icon } from '../components/Icon.jsx'
+import { useToasts } from '../components/Toasts.jsx'
import { useStore } from '../context.jsx'
export const ApiKeys = () => {
- const { showToast } = useStore()
+ const [showToast] = useToasts()
const [keys, setKeys] = useState([])
@@ -40,7 +41,7 @@ export const ApiKeys = () => {
await navigator.clipboard.writeText(key)
showToast(
<>
- Copiata
{key}
negli appunti
+ Copiata chiave
{key.substring(0, 6)}
... negli appunti
>
)
}
@@ -62,7 +63,7 @@ export const ApiKeys = () => {
{/* Header */}
-
+
{/* Rows */}
{keys.map(key => {
return (
@@ -72,7 +73,7 @@ export const ApiKeys = () => {
{key}
-
+
-