commit a4a3aa5eaa355c43f66e250c02829c33974407e0 parent 59e4d7e1873e701ef6041219bce0e0431e659de5 Author: Sebastian <sebasjm@gmail.com> Date: Mon, 22 Feb 2021 10:28:37 -0300 login with message and instanceContext Diffstat:
14 files changed, 191 insertions(+), 159 deletions(-)
diff --git a/packages/frontend/src/components/auth/index.tsx b/packages/frontend/src/components/auth/index.tsx @@ -20,14 +20,17 @@ */ import { h, VNode } from "preact"; +import { Text } from "preact-i18n"; import { useContext, useState } from "preact/hooks"; import { BackendContext } from "../../context/backend"; +import { Notification } from "../../declaration"; interface Props { + withMessage?: Notification; onConfirm: (backend: string, token?: string) => void; } -export function LoginModal({ onConfirm }: Props): VNode { +export function LoginModal({ onConfirm, withMessage }: Props): VNode { const backend = useContext(BackendContext) const [updatingToken, setUpdatingToken] = useState(false) const [token, setToken] = useState(backend.token || '') @@ -37,6 +40,16 @@ export function LoginModal({ onConfirm }: Props): VNode { return <div class="modal is-active is-clipped"> <div class="modal-background" /> <div class="modal-card"> + {withMessage && <div class={withMessage.type === 'ERROR' ? "notification is-danger" : "notification is-info"}> + <div class="columns is-vcentered"> + <div class="column is-12"> + <div> + <p><Text id={`notification.${withMessage.messageId}.title`} /> </p> + <Text id={`notification.${withMessage.messageId}.description`} fields={withMessage.params} /> + </div> + </div> + </div> + </div>} <header class="modal-card-head"> <p class="modal-card-title">Login required</p> </header> @@ -72,7 +85,7 @@ export function LoginModal({ onConfirm }: Props): VNode { </div> </div> </section> - <footer class="modal-card-foot " style={{justifyContent: 'flex-end'}}> + <footer class="modal-card-foot " style={{ justifyContent: 'flex-end' }}> <button class="button is-info" onClick={(): void => { onConfirm(url, updatingToken && token ? token : undefined); }} >Confirm</button> diff --git a/packages/frontend/src/components/notifications/index.tsx b/packages/frontend/src/components/notifications/index.tsx @@ -25,7 +25,7 @@ import { MessageType, Notification } from "../../declaration"; interface Props { notifications: Notification[]; - removeNotification: (n: Notification) => void; + removeNotification?: (n: Notification) => void; } function messageStyle(type: MessageType): string { @@ -43,7 +43,7 @@ export function Notifications({ notifications, removeNotification }: Props): VNo {notifications.map(n => <article class={messageStyle(n.type)}> <div class="message-header"> <p><Text id={`notification.${n.messageId}.title`} /> </p> - <button class="delete" onClick={()=> removeNotification(n)} /> + <button class="delete" onClick={()=> removeNotification && removeNotification(n)} /> </div> <div class="message-body"> <Text id={`notification.${n.messageId}.description`} fields={n.params} /> diff --git a/packages/frontend/src/context/backend.ts b/packages/frontend/src/context/backend.ts @@ -1,11 +1,13 @@ import { createContext } from 'preact' +import { StateUpdater } from 'preact/hooks' export interface BackendContextType { url: string; token?: string; changeBackend: (url: string) => void; - clearToken: () => void; - updateToken: (token:string) => void; + // clearTokens: () => void; + // addTokenCleaner: (c: StateUpdater<string | undefined>) => void; + updateToken: (token?:string) => void; lang: string; setLang: (lang: string) => void; } @@ -14,12 +16,18 @@ export interface ConfigContextType { currency?: string; } +export interface InstanceContextType { + id: string; + token?: string; +} + export const BackendContext = createContext<BackendContextType>({ url: '', lang: 'en', token: undefined, changeBackend: () => null, - clearToken: () => null, + // clearTokens: () => null, + // addTokenCleaner: () => null, updateToken: () => null, setLang: () => null, }) @@ -27,3 +35,8 @@ export const BackendContext = createContext<BackendContextType>({ export const ConfigContext = createContext<ConfigContextType>({ currency: undefined, }) + +export const InstanceContext = createContext<InstanceContextType>({ + id: '', + token: undefined, +}) +\ No newline at end of file diff --git a/packages/frontend/src/hooks/backend.ts b/packages/frontend/src/hooks/backend.ts @@ -23,7 +23,8 @@ import useSWR, { mutate } from 'swr'; import axios from 'axios' import { MerchantBackend } from '../declaration'; import { useContext } from 'preact/hooks'; -import { BackendContext } from '../context/backend'; +import { BackendContext, InstanceContext } from '../context/backend'; +import { useBackendInstanceToken } from '.'; type HttpResponse<T> = HttpResponseOk<T> | HttpResponseError<T>; @@ -71,8 +72,10 @@ function fetcher(url: string, token: string, backend: string) { interface BackendMutateAPI { createInstance: (data: MerchantBackend.Instances.InstanceConfigurationMessage) => Promise<void>; - updateInstance: (id: string, data: MerchantBackend.Instances.InstanceReconfigurationMessage) => Promise<void>; - deleteInstance: (id: string) => Promise<void>; +} +interface BackendInstaceMutateAPI { + updateInstance: (data: MerchantBackend.Instances.InstanceReconfigurationMessage) => Promise<void>; + deleteInstance: () => Promise<void>; } export function useBackendMutateAPI(): BackendMutateAPI { @@ -87,27 +90,35 @@ export function useBackendMutateAPI(): BackendMutateAPI { mutate('/private/instances') } - const updateInstance = async (updateId: string, instance: MerchantBackend.Instances.InstanceReconfigurationMessage): Promise<void> => { - await request(`${url}/private/instances/${updateId}`, { + return { createInstance } +} + +export function useBackendInstanceMutateAPI(): BackendInstaceMutateAPI { + const { url } = useContext(BackendContext) + const { id, token } = useContext(InstanceContext) + + const updateInstance = async (instance: MerchantBackend.Instances.InstanceReconfigurationMessage): Promise<void> => { + await request(`${url}/private/instances/${id}`, { method: 'patch', token, data: instance }) mutate('/private/instances', null) - mutate(`/private/instances/${updateId}`, null) + mutate(`/private/instances/${id}`, null) }; - const deleteInstance = async (deleteId: string): Promise<void> => { - await request(`${url}/private/instances/${deleteId}`, { + + const deleteInstance = async (): Promise<void> => { + await request(`${url}/private/instances/${id}`, { method: 'delete', token, }) mutate('/private/instances', null) - mutate(`/private/instances/${deleteId}`, null) + mutate(`/private/instances/${id}`, null) } - return { createInstance, updateInstance, deleteInstance } + return { updateInstance, deleteInstance } } export function useBackendInstances(): HttpResponse<MerchantBackend.Instances.InstancesResponse> { @@ -117,16 +128,19 @@ export function useBackendInstances(): HttpResponse<MerchantBackend.Instances.In return { data, unauthorized: error?.status === 401, error } } -export function useBackendInstance(id: string | null): HttpResponse<MerchantBackend.Instances.QueryInstancesResponse> { - const { url, token } = useContext(BackendContext) - const { data, error } = useSWR<MerchantBackend.Instances.QueryInstancesResponse>(id ? [`/private/instances/${id}`, token, url] : null, fetcher) +export function useBackendInstance(): HttpResponse<MerchantBackend.Instances.QueryInstancesResponse> { + const { url } = useContext(BackendContext); + const { id, token } = useContext(InstanceContext); + const { data, error } = useSWR<MerchantBackend.Instances.QueryInstancesResponse>([`/private/instances/${id}`, token, url], fetcher) return { data, unauthorized: error?.status === 401, error } } export function useBackendConfig(): HttpResponse<MerchantBackend.VersionResponse> { const { url, token } = useContext(BackendContext) - const { data, error } = useSWR<MerchantBackend.VersionResponse>(['/config', token, url], fetcher) + const { data, error } = useSWR<MerchantBackend.VersionResponse>(['/config', token, url], fetcher, { + shouldRetryOnError: false + }) return { data, unauthorized: error?.status === 401, error } } diff --git a/packages/frontend/src/hooks/notifications.ts b/packages/frontend/src/hooks/notifications.ts @@ -30,8 +30,8 @@ interface Result { type NotificationWithDate = Notification & { since: Date } -export function useNotifications(timeout = 3000): Result { - const [notifications, setNotifications] = useState<(NotificationWithDate)[]>([]) +export function useNotifications(initial: Notification[] = [], timeout = 3000): Result { + const [notifications, setNotifications] = useState<(NotificationWithDate)[]>(initial.map(i => ({...i, since: new Date() }))) const pushNotification = (n: Notification): void => { const entry = { ...n, since: new Date() } diff --git a/packages/frontend/src/i18n/index.ts b/packages/frontend/src/i18n/index.ts @@ -118,13 +118,17 @@ export const translations = { }, notification: { unauthorized: { - title: 'unauthorized access', - description: 'backend has denied access' + title: 'Could not access the backend', + description: 'backend has denied access, try using another token' }, error: { title: 'Error query the backend', description: 'Got message: "{{error.message}}" from: {{backend}} (hasToken: {{hasToken}})' }, + no_server: { + title: 'Could not access the backend', + description: `There was a problem trying to reach the backend. \n Got message: "{{error.message}}" from: {{backend}} (hasToken: {{hasToken}})` + }, create_error: { title: 'create error', description: 'the create process went wrong, server says: {{info.hint}}' diff --git a/packages/frontend/src/index.tsx b/packages/frontend/src/index.tsx @@ -22,7 +22,7 @@ import "./scss/main.scss" import { h, VNode } from 'preact'; -import { useContext, useEffect } from "preact/hooks"; +import { StateUpdater, useCallback, useContext, useEffect, useState } from "preact/hooks"; import { Route, Router, route } from 'preact-router'; import { IntlProvider } from 'preact-i18n'; @@ -33,7 +33,7 @@ import { Notifications } from './components/notifications'; import { translations } from './i18n'; import { useBackendURL, useBackendDefaultToken, useLang, useBackendInstanceToken } from './hooks'; import { useNotifications } from "./hooks/notifications"; -import { BackendContext } from './context/backend'; +import { BackendContext, ConfigContext, InstanceContext } from './context/backend'; import { useBackendConfig } from "./hooks/backend"; import NotFoundPage from './routes/notfound'; @@ -66,38 +66,42 @@ function Redirect({ to }: { to: string }): null { function AppRouting(): VNode { const { notifications, pushNotification, removeNotification } = useNotifications() - const { lang, setLang, clearToken, changeBackend, updateToken } = useContext(BackendContext) + const { lang, setLang, changeBackend, updateToken } = useContext(BackendContext) const backendConfig = useBackendConfig(); - const error = backendConfig.data || backendConfig.error - - useEffect(() =>{ - pushNotification({ - messageId: 'error', + const LoginWithError = () => <Login + withMessage={{ + messageId: 'no_server', type: 'ERROR', - params: error - }) - }, [error, pushNotification]) + params: !backendConfig.data ? backendConfig.error : {} + }} + onConfirm={(url: string, token?: string) => { + changeBackend(url) + if (token) updateToken(token) + route(RootPages.instances) + }} + /> + + const cleaner = useCallback(() =>{updateToken(undefined)},[]) + + const [cleaners, setCleaners] = useState([cleaner]) + const addTokenCleaner = (c:() => void) => setCleaners(cs => [...cs,c]) + const addTokenCleanerNemo = useCallback((c:() => void) =>{addTokenCleaner(c)},[cleaner]) return <div id="app"> - <NavigationBar lang={lang} setLang={setLang} onLogout={clearToken} /> - <Sidebar /> - <Notifications notifications={notifications} removeNotification={removeNotification} /> - {!backendConfig.data ? - <Route default - component={Login} - - onConfirm={(url: string, token?: string) => { - changeBackend(url) - if (token) updateToken(token) - route(RootPages.instances) - }} /> : - <Route default component={AppReady} pushNotification={pushNotification} /> - } + <ConfigContext.Provider value={backendConfig.data || {}}> + <NavigationBar lang={lang} setLang={setLang} onLogout={() => { cleaners.forEach( c => c() ) }} /> + <Sidebar /> + <Notifications notifications={notifications} removeNotification={removeNotification} /> + {!backendConfig.data ? + <Route default component={LoginWithError} /> : + <Route default component={AppReady} pushNotification={pushNotification} addTokenCleaner={addTokenCleanerNemo} /> + } + </ConfigContext.Provider> </div> } -function AppReady({ pushNotification }: { pushNotification: (n: Notification) => void }): VNode { +function AppReady({ pushNotification,addTokenCleaner }: { pushNotification: (n: Notification) => void, addTokenCleaner: any }): VNode { const { changeBackend, updateToken } = useContext(BackendContext) const updateLoginStatus = (url: string, token?: string) => { @@ -119,7 +123,10 @@ function AppReady({ pushNotification }: { pushNotification: (n: Notification) => route(`/instance/${id}/update`) }} - onUnauthorized={() => <Login onConfirm={updateLoginStatus} />} + onUnauthorized={() => <Login + withMessage={{ messageId: 'unauthorized', type: 'ERROR', }} + onConfirm={updateLoginStatus} + />} onError={(error: Error) => { pushNotification({ messageId: 'error', params: error, type: 'ERROR' }) @@ -141,7 +148,7 @@ function AppReady({ pushNotification }: { pushNotification: (n: Notification) => }} /> - <Route path={RootPages.instance_id_route} component={SubPages} pushNotification={pushNotification} /> + <Route path={RootPages.instance_id_route} component={SubPages} pushNotification={pushNotification} addTokenCleaner={addTokenCleaner} /> <Route default component={NotFoundPage} /> @@ -152,9 +159,8 @@ function useBackendContextState() { const [lang, setLang] = useLang() const [url, changeBackend] = useBackendURL(); const [token, updateToken] = useBackendDefaultToken(); - const clearToken = () => updateToken(undefined) - return { url, token, changeBackend, clearToken, updateToken, lang, setLang } + return { url, token, changeBackend, updateToken, lang, setLang } } export default function Application(): VNode { @@ -170,52 +176,70 @@ export default function Application(): VNode { interface SubPagesProps { id: string; pushNotification: (n: Notification) => void; + addTokenCleaner: any; } -function SubPages({ id, pushNotification }: SubPagesProps): VNode { - const [, updateToken] = useBackendInstanceToken(id); +function SubPages({ id, pushNotification, addTokenCleaner }: SubPagesProps): VNode { + const [token, updateToken] = useBackendInstanceToken(id); const { changeBackend } = useContext(BackendContext) + const cleaner = useCallback(() =>{updateToken(undefined)},[id]) + + useEffect(() => { + addTokenCleaner(cleaner) + }, [addTokenCleaner, cleaner]) + const updateLoginStatus = (url: string, token?: string) => { changeBackend(url) if (token) updateToken(token) } - return <Router> - <Route path={InstancePages.details} - component={Details} - onUnauthorized={() => <Login onConfirm={updateLoginStatus} />} - onUpdate={() => { - route(`/instance/${id}/update`) - }} - onLoadError={(e: Error) => { - pushNotification({ messageId: 'update_load_error', type: 'ERROR', params: e }) - route(`/instance/${id}/`) - return <div /> - }} - - /> - - <Route path={InstancePages.update} - component={Update} - onUnauthorized={() => <Login onConfirm={updateLoginStatus} />} - onLoadError={(e: Error) => { - pushNotification({ messageId: 'update_load_error', type: 'ERROR', params: e }) - route(`/instance/${id}/`) - return <div /> - }} - onBack={() => { - route(`/instance/${id}/`) - }} - onConfirm={() => { - pushNotification({ messageId: 'create_success', type: 'SUCCESS' }) - route(`/instance/${id}/`) - }} - onUpdateError={(e: Error) => { - pushNotification({ messageId: 'update_error', type: 'ERROR', params: e }) - }} - /> + return <InstanceContext.Provider value={{id, token}}> + <Router> + <Route path={InstancePages.details} + component={Details} + + onUnauthorized={() => <Login + withMessage={{ messageId: 'unauthorized', type: 'ERROR', }} + onConfirm={updateLoginStatus} + />} + + onUpdate={() => { + route(`/instance/${id}/update`) + }} + + onLoadError={(e: Error) => { + pushNotification({ messageId: 'update_load_error', type: 'ERROR', params: e }) + route(`/instance/${id}/`) + return <div /> + }} + /> + + <Route path={InstancePages.update} + component={Update} + onUnauthorized={() => <Login + withMessage={{ messageId: 'unauthorized', type: 'ERROR', }} + onConfirm={updateLoginStatus} + />} + onLoadError={(e: Error) => { + pushNotification({ messageId: 'update_load_error', type: 'ERROR', params: e }) + route(`/instance/${id}/`) + return <div /> + }} + onBack={() => { + route(`/instance/${id}/`) + }} + onConfirm={() => { + pushNotification({ messageId: 'create_success', type: 'SUCCESS' }) + route(`/instance/${id}/`) + }} + onUpdateError={(e: Error) => { + pushNotification({ messageId: 'update_error', type: 'ERROR', params: e }) + }} + /> + + <Route default component={NotFoundPage} /> + </Router> + </InstanceContext.Provider> - <Route default component={NotFoundPage} /> - </Router> } \ No newline at end of file diff --git a/packages/frontend/src/routes/instances/details/DetailPage.tsx b/packages/frontend/src/routes/instances/details/DetailPage.tsx @@ -30,7 +30,6 @@ interface Props { onUpdate: () => void; onDelete: () => void; selected: MerchantBackend.Instances.QueryInstancesResponse; - id: string, isLoading: boolean; } diff --git a/packages/frontend/src/routes/instances/details/index.tsx b/packages/frontend/src/routes/instances/details/index.tsx @@ -1,7 +1,8 @@ import { Fragment, h, VNode } from "preact"; -import { useState } from "preact/hooks"; +import { useContext, useState } from "preact/hooks"; +import { InstanceContext } from "../../../context/backend"; import { Notification } from "../../../declaration"; -import { useBackendInstance, useBackendMutateAPI } from "../../../hooks/backend"; +import { useBackendInstance, useBackendInstanceMutateAPI } from "../../../hooks/backend"; import { DeleteModal } from "../list/DeleteModal"; import { DetailPage } from "./DetailPage"; @@ -9,15 +10,15 @@ interface Props { onUnauthorized: () => VNode; onLoadError: (e: Error) => VNode; onUpdate: () => void; - id: string; pushNotification: (n: Notification) => void; } -export default function Detail({ onUpdate, onLoadError, onUnauthorized, id, pushNotification }: Props): VNode { - const details = useBackendInstance(id) +export default function Detail({ onUpdate, onLoadError, onUnauthorized, pushNotification }: Props): VNode { + const { id } = useContext(InstanceContext) + const details = useBackendInstance() const [deleting, setDeleting] = useState<boolean>(false) - const { deleteInstance } = useBackendMutateAPI() + const { deleteInstance } = useBackendInstanceMutateAPI() if (!details.data) { if (details.unauthorized) return onUnauthorized() @@ -30,16 +31,16 @@ export default function Detail({ onUpdate, onLoadError, onUnauthorized, id, push return <Fragment> <DetailPage isLoading={false} - selected={details.data} id={id} + selected={details.data} onUpdate={onUpdate} onDelete={() => setDeleting(true) } /> {deleting && <DeleteModal element={{name: details.data.name, id }} onCancel={() => setDeleting(false) } - onConfirm={async (id: string): Promise<void> => { + onConfirm={async (): Promise<void> => { try { - await deleteInstance(id) + await deleteInstance() pushNotification({ messageId: 'delete_success', type: 'SUCCESS' }) } catch (error) { pushNotification({ messageId: 'delete_error', type: 'ERROR', params: error }) diff --git a/packages/frontend/src/routes/instances/list/index.tsx b/packages/frontend/src/routes/instances/list/index.tsx @@ -21,7 +21,7 @@ import { Fragment, h, VNode } from 'preact'; import { View } from './View'; -import { useBackendInstances, useBackendMutateAPI } from '../../../hooks/backend'; +import { useBackendInstances, useBackendInstanceMutateAPI } from '../../../hooks/backend'; import { useState } from 'preact/hooks'; import { MerchantBackend, Notification } from '../../../declaration'; import { DeleteModal } from './DeleteModal'; @@ -36,53 +36,16 @@ interface Props { export default function Instances({ pushNotification, onUnauthorized, onError, onCreate, onUpdate }: Props): VNode { const list = useBackendInstances() const [deleting, setDeleting] = useState<MerchantBackend.Instances.Instance | null>(null) - // const details = useBackendInstance(selectedId) - // const [create, setCreate] = useState<boolean>(false) - // const [update, setUpdate] = useState<boolean>(false) - const { deleteInstance } = useBackendMutateAPI() + const { deleteInstance } = useBackendInstanceMutateAPI() - // || (selectedId != null && !details.data && details.unauthorized) const isLoadingTheList = (!list.data && !list.error) - // const isLoadingTheDetails = (!details.data && !details.error) const error = !list.data && list.error - // || !details.data && details.error if (!list.data) { if (list.unauthorized) return onUnauthorized() if (list.error) return onError(list.error) } - // if (create) { - // return <CreatePage - // goBack={() => setCreate(false)} - // isLoading={false} - - // onCreate={(d): Promise<void> => list.create(d) - // .then((): void => pushNotification({ messageId: 'create_success', type: 'SUCCESS' })) - // .catch((error): void => pushNotification({ messageId: 'create_error', type: 'ERROR', params: error })) - // } - // /> - // } - - // if (update && details.data && selectedId) { - // return <UpdatePage - // goBack={() => setUpdate(false)} - // isLoading={false} - // selected={{ ...details.data, id: selectedId }} - // onUpdate={(id, d): Promise<void> => details.update(id, d) - // .then((): void => pushNotification({ messageId: 'update_success', type: 'SUCCESS' })) - // .catch((error): void => pushNotification({ messageId: 'update_error', type: 'ERROR', params: error })) - // } - // /> - // } - // {selected && action === 'DELETE' ? - - // : null} - - // (id): Promise<void> => deleteInstance(id) - // .then((): void => pushNotification({ messageId: 'delete_success', type: 'SUCCESS' })) - // .catch((error): void => pushNotification({ messageId: 'delete_error', type: 'ERROR', params: error })) - return <Fragment> <View instances={list.data?.instances || []} isLoading={isLoadingTheList} @@ -94,9 +57,9 @@ export default function Instances({ pushNotification, onUnauthorized, onError, o {deleting && <DeleteModal element={deleting} onCancel={() => setDeleting(null) } - onConfirm={async (id: string): Promise<void> => { + onConfirm={async (): Promise<void> => { try { - await deleteInstance(id) + await deleteInstance() pushNotification({ messageId: 'delete_success', type: 'SUCCESS' }) } catch (e) { pushNotification({ messageId: 'delete_error', type: 'ERROR', params: error }) diff --git a/packages/frontend/src/routes/instances/update/UpdatePage.tsx b/packages/frontend/src/routes/instances/update/UpdatePage.tsx @@ -28,9 +28,8 @@ import { InstanceUpdateSchema as schema } from '../../../schemas' import { Text } from "preact-i18n"; interface Props { - onUpdate: (id: string, d: MerchantBackend.Instances.InstanceReconfigurationMessage) => void; + onUpdate: (d: MerchantBackend.Instances.InstanceReconfigurationMessage) => void; selected: MerchantBackend.Instances.QueryInstancesResponse; - id: string, isLoading: boolean; onBack: () => void; } @@ -50,14 +49,14 @@ function convert(from: MerchantBackend.Instances.QueryInstancesResponse): Mercha return { ...defaults, ...rest, payto_uris }; } -export function UpdatePage({ onUpdate, isLoading, selected, id, onBack }: Props): VNode { +export function UpdatePage({ onUpdate, isLoading, selected, onBack }: Props): VNode { const [value, valueHandler] = useState(convert(selected)) const [errors, setErrors] = useState<KeyValue>({}) const submit = (): void => { try { schema.validateSync(value, { abortEarly: false }) - onUpdate(id, schema.cast(value)); + onUpdate(schema.cast(value)); onBack() } catch (err) { const errors = err.inner as yup.ValidationError[] diff --git a/packages/frontend/src/routes/instances/update/index.tsx b/packages/frontend/src/routes/instances/update/index.tsx @@ -1,6 +1,6 @@ import { h, VNode } from "preact"; import { MerchantBackend } from "../../../declaration"; -import { useBackendInstance, useBackendMutateAPI } from "../../../hooks/backend"; +import { useBackendInstance, useBackendInstanceMutateAPI } from "../../../hooks/backend"; import { UpdatePage } from "./UpdatePage"; interface Props { @@ -12,12 +12,11 @@ interface Props { onLoadError: (e: Error) => VNode; onUpdateError: (e: Error) => void; - id: string; } -export default function Update({ onBack, onConfirm, onLoadError, onUpdateError, onUnauthorized, id }: Props): VNode { - const { updateInstance } = useBackendMutateAPI(); - const details = useBackendInstance(id) +export default function Update({ onBack, onConfirm, onLoadError, onUpdateError, onUnauthorized }: Props): VNode { + const { updateInstance } = useBackendInstanceMutateAPI(); + const details = useBackendInstance() if (!details.data) { if (details.unauthorized) return onUnauthorized() @@ -30,8 +29,8 @@ export default function Update({ onBack, onConfirm, onLoadError, onUpdateError, return <UpdatePage onBack={onBack} isLoading={false} - selected={details.data} id={id} - onUpdate={(id: string, d: MerchantBackend.Instances.InstanceReconfigurationMessage): Promise<void> => { - return updateInstance(id, d).then(onConfirm).catch(onUpdateError) + selected={details.data} + onUpdate={(d: MerchantBackend.Instances.InstanceReconfigurationMessage): Promise<void> => { + return updateInstance(d).then(onConfirm).catch(onUpdateError) }} /> } \ No newline at end of file diff --git a/packages/frontend/src/routes/login/index.tsx b/packages/frontend/src/routes/login/index.tsx @@ -1,9 +1,11 @@ import { h, VNode } from "preact"; import { LoginModal } from '../../components/auth'; +import { Notification } from "../../declaration"; interface Props { + withMessage?: Notification; onConfirm: (url: string, token?: string) => void; } -export default function LoginPage({onConfirm}: Props):VNode { - return <LoginModal onConfirm={onConfirm} /> +export default function LoginPage({ onConfirm, withMessage }: Props): VNode { + return <LoginModal onConfirm={onConfirm} withMessage={withMessage} /> } \ No newline at end of file diff --git a/packages/frontend/tests/hooks/notification.test.ts b/packages/frontend/tests/hooks/notification.test.ts @@ -28,7 +28,7 @@ test('notification should disapear after timeout', () => { jest.spyOn(global, 'setTimeout'); const timeout = 1000 - const { result, rerender } = renderHook(() => useNotifications(timeout)); + const { result, rerender } = renderHook(() => useNotifications(undefined, timeout)); expect(result.current?.notifications.length).toBe(0);