Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 21 additions & 12 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import languages from "../i18n/languages";
import opencastLogo from "../img/opencast-white.svg?url";
import { setSpecificServiceFilter } from "../slices/tableFilterSlice";
import { getErrorCount, getHealthStatus } from "../selectors/healthSelectors";
import { getRegistration } from "../selectors/registrationSelectors";
import {
getOrgProperties,
getUserInformation,
Expand All @@ -19,6 +20,9 @@ import HotKeyCheatSheet from "./shared/HotKeyCheatSheet";
import { useHotkeys } from "react-hotkeys-hook";
import { useAppDispatch, useAppSelector } from "../store";
import { HealthStatus, fetchHealthStatus } from "../slices/healthSlice";
import {
fetchRegistration,
} from "../slices/registrationSlice";
import { UserInfoState } from "../slices/userInfoSlice";
import { Tooltip } from "./shared/Tooltip";
import { HiOutlineTranslate } from "react-icons/hi";
Expand Down Expand Up @@ -51,13 +55,18 @@ const Header = () => {
const healthStatus = useAppSelector(state => getHealthStatus(state));
const errorCounter = useAppSelector(state => getErrorCount(state));
const user = useAppSelector(state => getUserInformation(state));
const registration = useAppSelector(state => getRegistration(state));
const orgProperties = useAppSelector(state => getOrgProperties(state));
const displayTerms = (orgProperties["org.opencastproject.admin.display_terms"] || "false").toLowerCase() === "true";

const loadHealthStatus = async () => {
await dispatch(fetchHealthStatus());
};

useEffect(() => {
dispatch(fetchRegistration());
}, [dispatch]);

const hideMenuHelp = () => {
setMenuHelp(false);
};
Expand Down Expand Up @@ -134,18 +143,18 @@ const Header = () => {
}, []);

useEffect(() => {
if (!user) { return; }

const isAdmin = user.isAdmin || user.isOrgAdmin;
const isLocalhost = window.location.hostname === "localhost";
const lastDismissed = localStorage.getItem("adopterModalDismissed");
const THIRTY_DAYS = 30 * 24 * 60 * 60 * 1000;
const dismissedLongEnough = !lastDismissed || Date.now() - parseInt(lastDismissed) > THIRTY_DAYS;

if (isAdmin && !isLocalhost && dismissedLongEnough) {
showRegistrationModal();
}
}, [user]);
if (!user) { return; }

const isAdmin = user.isAdmin || user.isOrgAdmin;
const isLocalhost = window.location.hostname === "localhost";
const lastDismissed = localStorage.getItem("adopterModalDismissed");
const THIRTY_DAYS = 30 * 24 * 60 * 60 * 1000;
const dismissedLongEnough = !lastDismissed || Date.now() - parseInt(lastDismissed) > THIRTY_DAYS;

if (isAdmin && !isLocalhost && dismissedLongEnough && registration == null) {
showRegistrationModal();
}
}, [user, registration]);
return (
<>
<header className="primary-header">
Expand Down
7 changes: 7 additions & 0 deletions src/selectors/registrationSelectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { RootState } from "../store";

/**
* This file contains selectors regarding information about the registration status
*/
// Are we registered at all
export const getRegistration = (state: RootState) => state.registration.registration;
52 changes: 52 additions & 0 deletions src/slices/registrationSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import axios from "axios";
import { createAppAsyncThunk } from "../createAsyncThunkWithTypes";

export type Registration = {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since all this PR really does is checking if ´/admin-ng/adopter/registration` returns null or not, creating a whole redux state is complete overkill. If you'll need this for some other PR, would it not be better to add it then?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair. The goal here is to be able to set warnings in the notification bell in a few cases. I'll rework this and come back when it's ready.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this more what you're looking for @Arnei? Or are you wanting me to completely remove the slice and selectors? There's an adopterRegistrationUtils file which powers the modal and works, but I just can't seem to get the relevant function(s) to work from the header...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of completely removing the slice and selectors and stuff, and do something like in About.tsx, aka just do the state thing locally in the component.

If you plan to make use of redux state in a later PR, it might make sense to use redux right now already, so you don't have to do work twice. But as a reviewer, I can't know that :D

agreedToPolicy: boolean,
registered: boolean,
termsVersionAgreed: string,
}

export type RegistrationState = {
registration: boolean | null,
error: boolean
};

// Initial state of health status in redux store
const initialState: RegistrationState = {
registration: null,
error: false,
};

// This is the registration itself
export const fetchRegistration = createAppAsyncThunk("registration/fetchRegistration", async () => {
const res = await axios.get<Registration>("/admin-ng/adopter/registration");
return res.data;
});

const registrationSlice = createSlice({
name: "registration",
initialState,
reducers: {
setError(state, action: PayloadAction<{
error: RegistrationState["error"],
}>) {
state.error = action.payload.error;
},
},
// These are used for thunks
extraReducers: builder => {
builder
.addCase(fetchRegistration.fulfilled, (state, _action: PayloadAction<
Registration
>) => {
state.registration = true;
});
},
});

export const { setError } = registrationSlice.actions;

// Export the slice reducer as the default export
export default registrationSlice.reducer;
2 changes: 2 additions & 0 deletions src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import groups from "./slices/groupSlice";
import acls from "./slices/aclSlice";
import themes from "./slices/themeSlice";
import health from "./slices/healthSlice";
import registration from "./slices/registrationSlice";
import notifications from "./slices/notificationSlice";
import workflows from "./slices/workflowSlice";
import eventDetails from "./slices/eventDetailsSlice";
Expand Down Expand Up @@ -64,6 +65,7 @@ const reducers = combineReducers({
acls: persistReducer(aclsPersistConfig, acls),
themes: persistReducer(themesPersistConfig, themes),
health,
registration,
notifications,
workflows,
eventDetails,
Expand Down
Loading