Skip to content

Commit

Permalink
fix(map): do not reload while editing text of feature (#579)
Browse files Browse the repository at this point in the history
  • Loading branch information
nimdanitro authored Dec 17, 2024
1 parent 1fe871c commit 78f7f7f
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 63 deletions.
44 changes: 4 additions & 40 deletions ui/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { lazy, Suspense, useEffect, useState } from "react";
import { lazy, Suspense } from "react";
import { Navigate, Route, HashRouter as Router, Routes } from "react-router-dom";

import "./App.scss";
Expand All @@ -18,9 +18,7 @@ import { List as ResourcesList } from "views/resource";

import { ApolloProvider } from "@apollo/client";
import { Spinner } from "components";
import { useTranslation } from "react-i18next";
import { UserState } from "types";
import { UserContext } from "utils";
import { UserProvider } from "utils";
import MessageSheet from "views/journal/MessageSheet";
import { Layout, LayoutMarginLess } from "views/Layout";
import { default as client } from "client";
Expand All @@ -29,42 +27,8 @@ import { Provider as FeatureFlagProvider } from "FeatureFlags";
const Map = lazy(() => import("views/map"));

function App() {
const [userState, setUserState] = useState<UserState>({ isLoggedin: false, email: "", username: "" });
const { i18n } = useTranslation();

const setUserStateFromUserinfo = () => {
fetch("/oauth2/userinfo", { credentials: "include" })
.then((response) => {
if (!response.ok) {
throw new Error("unauthenticated");
}
return response.json();
})
.then((userInfo) => {
setUserState({
isLoggedin: true,
email: userInfo.email,
username: userInfo.user || userInfo.preferredUsername,
});
})
.catch(() => {
setUserState({ isLoggedin: false, email: "", username: "" });
});
};

useEffect(() => {
setUserStateFromUserinfo();
i18n.changeLanguage();

const interval = setInterval(() => {
setUserStateFromUserinfo();
}, 10000);

return () => clearInterval(interval);
}, [i18n]);

return (
<UserContext.Provider value={userState}>
<UserProvider>
<ApolloProvider client={client}>
<FeatureFlagProvider>
<Router>
Expand Down Expand Up @@ -189,7 +153,7 @@ function App() {
</Router>
</FeatureFlagProvider>
</ApolloProvider>
</UserContext.Provider>
</UserProvider>
);
}

Expand Down
7 changes: 1 addition & 6 deletions ui/src/FeatureFlags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const localFlagConfig = {

const Provider = (props: PropsWithChildren) => {
const { children } = props;
const userState = useContext(UserContext);
const { state: userState } = useContext(UserContext);

useEffect(() => {
const fliptProvider = new FliptWebProvider("sitrep-ui", { url: "https://flipt.sitrep.ch" });
Expand All @@ -38,11 +38,6 @@ const Provider = (props: PropsWithChildren) => {
email: userState.email,
};
OpenFeature.setContext(context);

return () => {
console.log("closing openfeature provider");
OpenFeature.close();
};
}, [userState]);

return <OpenFeatureProvider>{children}</OpenFeatureProvider>;
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ function VersionNavBar() {
}

function UserNavBar() {
const userState = useContext(UserContext);
const { state: userState } = useContext(UserContext);
const { t } = useTranslation();

if (!userState.isLoggedin) return <></>;
Expand Down
97 changes: 94 additions & 3 deletions ui/src/utils/UserContext.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,96 @@
import { createContext } from "react";
import { createContext, useReducer, useEffect, useCallback, useContext, ReactNode, Dispatch } from "react";
import { UserState } from "types";
const UserContext = createContext<UserState>({ isLoggedin: false, username: "", email: "" });

export { UserContext };
// Define the initial state
const initialState: UserState = { isLoggedin: false, username: "", email: "" };

// Define action types
type UserAction = { type: "LOGIN"; payload: { username: string; email: string } } | { type: "LOGOUT" };

// Define the reducer function
const userReducer = (state: UserState, action: UserAction): UserState => {
switch (action.type) {
case "LOGIN":
return {
isLoggedin: true,
username: action.payload.username,
email: action.payload.email,
};
case "LOGOUT":
return {
isLoggedin: false,
username: "",
email: "",
};
default:
return state;
}
};

// Create the UserContext with initial state and a dummy dispatch function
const UserContext = createContext<{
state: UserState;
dispatch: Dispatch<UserAction>;
}>({
state: initialState,
dispatch: () => null,
});

// Create the UserProvider component
const UserProvider = ({ children }: { children: ReactNode }) => {
const [state, dispatch] = useReducer(userReducer, initialState);

return (
<UserContext.Provider value={{ state, dispatch }}>
<UserInfoFetcher />
{children}
</UserContext.Provider>
);
};

const UserInfoFetcher = () => {
const { state: userState, dispatch } = useContext(UserContext);
const setUserStateFromUserinfo = useCallback(() => {
fetch("/oauth2/userinfo", { credentials: "include" })
.then((response) => {
if (!response.ok) {
throw new Error("unauthenticated");
}
return response.json();
})
.then((userInfo) => {
const newUserState = {
isLoggedin: true,
email: userInfo.email,
username: userInfo.user || userInfo.preferredUsername,
};

// Only update state if it has changed
if (
newUserState.isLoggedin !== userState.isLoggedin ||
newUserState.email !== userState.email ||
newUserState.username !== userState.username
) {
dispatch({ type: "LOGIN", payload: newUserState });
}
})
.catch(() => {
if (userState.isLoggedin) {
dispatch({ type: "LOGOUT" });
}
});
}, [userState, dispatch]);

useEffect(() => {
setUserStateFromUserinfo();
const interval = setInterval(() => {
setUserStateFromUserinfo();
}, 30000);

return () => clearInterval(interval);
}, [userState]);

return <></>;
};

export { UserContext, UserProvider };
2 changes: 1 addition & 1 deletion ui/src/utils/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export { UserContext } from "./UserContext";
export { UserContext, UserProvider } from "./UserContext";

export { ReloadPrompt } from "./ReloadSWPrompt";
4 changes: 2 additions & 2 deletions ui/src/views/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface LayoutProps {
export const Layout = (props: LayoutProps) => {
const [searchParams] = useSearchParams();
const { i18n } = useTranslation();
const userState = useContext(UserContext);
const { state: userState } = useContext(UserContext);

const lang = searchParams.get("lang");
useEffect(() => {
Expand All @@ -40,7 +40,7 @@ export const Layout = (props: LayoutProps) => {
export const LayoutMarginLess = (props: LayoutProps) => {
const [searchParams] = useSearchParams();
const { i18n } = useTranslation();
const userState = useContext(UserContext);
const { state: userState } = useContext(UserContext);

const lang = searchParams.get("lang");
useEffect(() => {
Expand Down
14 changes: 8 additions & 6 deletions ui/src/views/map/Map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,19 +97,19 @@ function Layers() {
const { state } = useContext(LayerContext);

return (
<LayersProvider>
<LayerFetcher />
<>
<div className="maplibregl-ctrl-bottom-right">
<LayerControl />
<StyleController />
</div>

{/* Active Layer */}
<ActiveLayer />
<BabsIconController />

{/* Inactive Layers */}
<InactiveLayers layers={state.layers.filter((l) => l.id !== state.activeLayer) || []} />
</LayersProvider>
</>
);
}

Expand All @@ -120,7 +120,7 @@ function LayerFetcher() {

const { data, loading } = useQuery<GetLayersData, GetLayersVars>(GetLayers, {
variables: { incidentId: incidentId || "" },
pollInterval: 3000,
pollInterval: 2000,
fetchPolicy: "cache-and-network",
});

Expand Down Expand Up @@ -170,7 +170,6 @@ function ActiveLayer() {
featureCollection={featureCollection}
selectedFeature={state.selectedFeature}
/>
<BabsIconController />
</>
);
}
Expand Down Expand Up @@ -397,7 +396,10 @@ function InactiveLayer(props: { featureCollection: FeatureCollection; id: string
function MapWithProvder() {
return (
<MapProvider>
<MapView />
<LayersProvider>
<MapView />
<LayerFetcher />
</LayersProvider>
</MapProvider>
);
}
Expand Down
7 changes: 3 additions & 4 deletions ui/src/views/map/controls/BabsIconController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -521,13 +521,12 @@ const FeatureDetailControlPanel = memo((props: BabsIconControllerProps) => {
return (
<div className="maplibregl-ctrl maplibregl-ctrl-top-right control-panel">
<h5 className="title is-5">Name</h5>
<div className="control has-icons-left has-icons-right">
<div className="control has-icons-left has-icons-right mb-1">
<input
className="input is-small"
type="email"
placeholder="Signaturtext"
type="text"
placeholder="Name"
onChange={(e) => {
e.preventDefault();
setEnteredText(e.target.value);
}}
value={enteredText}
Expand Down

0 comments on commit 78f7f7f

Please sign in to comment.