diff --git a/plugins/player_sync/web/index.tsx b/plugins/player_sync/web/index.tsx index 49535e6a..38f101fc 100644 --- a/plugins/player_sync/web/index.tsx +++ b/plugins/player_sync/web/index.tsx @@ -84,20 +84,30 @@ function InventoryTable(props: { name: string, items: ItemSummary[] }) { } function PlayerDrawer(props: { playerName?: string, onClose: () => void, onChange: () => void }) { + return + {/* Keyed so a request that finishes after switching players can only update the old player's view */} + {props.playerName !== undefined + && } + ; +} + +function PlayerDetails(props: { playerName: string, onChange: () => void }) { const control = useContext(ControlContext); const account = useAccount(); const instanceName = useInstanceName(); const [response, setResponse] = useState(); const { playerName } = props; - // Only the latest request may set the response, older ones may be for another player + // Only the latest request may set the response, an import or delete can finish after a reload const requestId = useRef(0); const reload = useCallback(() => { requestId.current += 1; let id = requestId.current; - if (playerName === undefined) { - return; - } control.send(new GetPlayerDataRequest(playerName)).then(result => { if (id === requestId.current) { setResponse(result); @@ -106,10 +116,7 @@ function PlayerDrawer(props: { playerName?: string, onClose: () => void, onChang notifyErrorHandler("Error loading player data") ); }, [control, playerName]); - useEffect(() => { - setResponse(undefined); - reload(); - }, [reload]); + useEffect(reload, [reload]); function changed() { reload(); @@ -124,9 +131,9 @@ function PlayerDrawer(props: { playerName?: string, onClose: () => void, onChang notify("Invalid JSON", "error", err.message); return; } - playerData.name = playerName!; + playerData.name = playerName; playerData.generation ??= 0; - let result = await control.send(new SetPlayerDataRequest(playerName!, playerData)); + let result = await control.send(new SetPlayerDataRequest(playerName, playerData)); notify(`Stored player data for ${playerName} as generation ${result.generation}`); changed(); } @@ -144,12 +151,7 @@ function PlayerDrawer(props: { playerName?: string, onClose: () => void, onChang const canModify = account.hasPermission("player_sync.inventory.modify"); const playerData = response?.playerData; const acquiredBy = response?.instanceId !== undefined ? instanceName(response.instanceId) : undefined; - return + return <> {response && {acquiredBy !== undefined && void, onChang } action={canModify && control.send(new ForceReleaseRequest(playerName!)).then(changed).catch( + onConfirm={() => control.send(new ForceReleaseRequest(playerName)).then(changed).catch( notifyErrorHandler("Error releasing lock") )} > @@ -195,7 +197,7 @@ function PlayerDrawer(props: { playerName?: string, onClose: () => void, onChang } okText="Delete" okButtonProps={{ danger: true }} - onConfirm={() => control.send(new DeletePlayerDataRequest(playerName!)).then(changed).catch( + onConfirm={() => control.send(new DeletePlayerDataRequest(playerName)).then(changed).catch( notifyErrorHandler("Error deleting player data") )} > @@ -207,7 +209,7 @@ function PlayerDrawer(props: { playerName?: string, onClose: () => void, onChang inventory => )} } - ; + ; } function InventoryPage() {