Files
TREK/client/src/components/Files/docsync/useDocSyncOffered.ts
T
Maurice 843582863c fix(docsync): offer the sync button only where something is behind it
The Documents addon put a "Document sync" button on every trip's Files
tab, and the seed ships every provider switched off, so after the
upgrade each of those buttons led into "No document providers are
available". The button now shows on a trip that is already bound, to
every member, and otherwise only to somebody who may bind the trip on
an instance that offers a provider. Without it the Files toolbar is
the one from before the feature, trash flush right, on both shells.

/api/addons carries no document providers for a normal user, so the
answer comes from the docsync routes through a new online-only
docSyncRepo and is kept per session in docSyncOfferStore. A revisit
renders the last answer at once and checks it again; offline nothing
is asked and the last answer stands. Creating a binding, removing one
and removing a connection now ping the trip with docsync:changed and
zero counts, so a member already on the Files tab sees the button come
and go without leaving it.

Both shells keep listing a binding whose provider the admin has since
switched off instead of claiming there are no providers, and name its
store through one storeName() helper. A load that answers 403 or 404
clears the bindings as well, so they do not linger once the Documents
addon is gone.

The phone admin screen gets the Documents shelf the desktop one has:
the document providers as sub rows under the addon, toggled through the
same admin route and re-read after Documents itself is toggled, because
the server switches the providers off with it.

isTripOwner and the isOwner prop become canManageSync and canManage,
which is what canManageDocSync answers. Both folder pickers take
loadScopes out of the sync object before their effect, so
exhaustive-deps is satisfied without the effect running on every
render.
2026-09-19 13:36:33 +02:00

35 lines
1.5 KiB
TypeScript

import { useEffect } from 'react'
import { useNetworkMode } from '../../../hooks/useNetworkMode'
import { useDocSyncOfferStore } from '../../../store/docSyncOfferStore'
import { useServerPing } from '../../../sync/useServerPing'
/**
* Whether this trip's Files screen shows the "Document sync" button.
*
* One hook for both shells, so the toolbar and the phone header cannot drift
* on who sees it. The last known answer renders straight away; the server is
* asked again when the screen mounts and when the connection comes back, and
* never while offline, where the button keeps whatever it last knew.
*
* It is also asked on every `docsync:changed`, which the server sends when a
* binding comes or goes. A member can sit on the Files tab while the owner
* binds the trip, and on desktop that tab may never remount before a reload.
*/
export function useDocSyncOffered(tripId: number | string, canManage: boolean): boolean {
const offered = useDocSyncOfferStore(
s => s.bound[String(tripId)] === true || (canManage && s.providers === true),
)
const refresh = useDocSyncOfferStore(s => s.refresh)
const { offline } = useNetworkMode()
useEffect(() => {
if (!offline) void refresh(tripId, canManage)
}, [tripId, canManage, offline, refresh])
// Off while offline: the effect above already asks on the way back, and the
// ping's own return-to-online refetch would only ask a second time.
useServerPing('docsync:changed', !offline, () => refresh(tripId, canManage))
return offered
}