add redux state for settings

This commit is contained in:
Alex Holliday
2024-09-26 16:18:25 +08:00
parent 0832e8438a
commit 179e95eefe
3 changed files with 175 additions and 1 deletions

View File

@@ -0,0 +1,119 @@
import { networkService } from "../../main";
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { jwtDecode } from "jwt-decode";
import axios from "axios";
const initialState = {
isLoading: false,
apiBaseUrl: "http://localhost:5000/api/v1",
logLevel: "debug",
clientHost: "http://localhost:5173",
jwtSecret: "my_secret",
dbType: "MongoDB",
dbConnectionString: "mongodb://localhost:27017/uptime_db",
redisHost: "127.0.0.1",
redisPort: 6379,
jwtTTL: "99d",
pagespeedApiKey: "",
systemEmailHost: "smtp.gmail.com",
systemEmailPort: 465,
systemEmailAddress: "",
systemEmailPassword: "",
};
export const getAppSettings = createAsyncThunk(
"settings/getSettings",
async (data, thunkApi) => {
try {
const res = await networkService.getAppSettings({
authToken: data.authToken,
});
return res.data;
} catch (error) {
if (error.response.data) {
return thunkApi.rejectWithValue(error.response.data);
}
const payload = {
status: false,
msg: error.message ? error.message : "Unknown error",
};
return thunkApi.rejectWithValue(payload);
}
}
);
export const updateAppSettings = createAsyncThunk(
"settings/updateSettings",
async (form, thunkApi) => {
try {
const res = await networkService.loginUser(form);
return res.data;
} catch (error) {
if (error.response && error.response.data) {
return thunkApi.rejectWithValue(error.response.data);
}
const payload = {
status: false,
msg: error.message ? error.message : "Unknown error",
};
return thunkApi.rejectWithValue(payload);
}
}
);
const handleGetSettingsFulfilled = (state, action) => {
state.isLoading = false;
state.success = action.payload.success;
state.msg = action.payload.msg;
};
const handleGetSettingsRejected = (state, action) => {
state.isLoading = false;
state.success = false;
state.msg = action.payload ? action.payload.msg : "Failed to get settings.";
};
const handleUpdateSettingsFulfilled = (state, action) => {
state.isLoading = false;
state.success = action.payload.success;
state.msg = action.payload.msg;
};
const handleUpdateSettingsRejected = (state, action) => {
state.isLoading = false;
state.success = false;
state.msg = action.payload
? action.payload.msg
: "Failed to update settings.";
};
const settingsSlice = createSlice({
name: "settings",
initialState,
reducers: {
clearAuthState: (state) => {
state.authToken = "";
state.user = "";
state.isLoading = false;
state.success = true;
state.msg = "Logged out successfully";
},
},
extraReducers: (builder) => {
// Register thunk
builder
.addCase(getAppSettings.pending, (state) => {
state.isLoading = true;
})
.addCase(getAppSettings.fulfilled, handleGetSettingsFulfilled)
.addCase(getAppSettings.rejected, handleGetSettingsRejected);
// Login thunk
builder
.addCase(updateAppSettings.pending, (state) => {
state.isLoading = true;
})
.addCase(updateAppSettings.fulfilled, handleUpdateSettingsFulfilled)
.addCase(updateAppSettings.rejected, handleUpdateSettingsRejected);
},
});
export default settingsSlice.reducer;
export const { clearAuthState } = settingsSlice.actions;

View File

@@ -13,11 +13,12 @@ import {
deleteAllMonitors,
} from "../../Features/UptimeMonitors/uptimeMonitorsSlice";
import { update } from "../../Features/Auth/authSlice";
import { getAppSettings } from "../../Features/Settings/settingsSlice";
import PropTypes from "prop-types";
import LoadingButton from "@mui/lab/LoadingButton";
import { setTimezone } from "../../Features/UI/uiSlice";
import timezones from "../../Utils/timezones.json";
import { useState } from "react";
import { useEffect, useState } from "react";
import { ConfigBox } from "./styled";
import { networkService } from "../../main";
import { settingsValidation } from "../../Validation/validation";
@@ -35,9 +36,25 @@ const Settings = ({ isAdmin }) => {
const [form, setForm] = useState({
ttl: checkTTL ? (checkTTL / SECONDS_PER_DAY).toString() : 0,
});
const [settings, setSettings] = useState({
apiBaseUrl: "",
});
const [errors, setErrors] = useState({});
const dispatch = useDispatch();
useEffect(() => {
const fetchSettings = async () => {
const action = await dispatch(getAppSettings({ authToken }));
if (getAppSettings.fulfilled.match(action)) {
const settings = action.payload.data;
setSettings(settings);
} else if (getAppSettings.rejected.match(action)) {
throw new Error(action.error.message);
}
};
fetchSettings();
}, [dispatch, authToken]);
const handleChange = (event) => {
const { value, id } = event.target;
const { error } = settingsValidation.validate(
@@ -249,6 +266,23 @@ const Settings = ({ isAdmin }) => {
</Stack>
</ConfigBox>
)}
<ConfigBox>
<Box>
<Typography component="h1">Client Settings</Typography>
<Typography sx={{ mt: theme.spacing(2) }}>
Here you can modify settings for the client.
</Typography>
</Box>
<Stack gap={theme.spacing(20)}>
<Field
id="apiBaseUrl"
label="Base URL for backend API"
value={settings.apiBaseUrl}
onChange={handleChange}
error={errors["settings-client-base-url"]}
/>
</Stack>
</ConfigBox>
<ConfigBox>
<Box>
<Typography component="h1">About</Typography>

View File

@@ -619,6 +619,27 @@ class NetworkService {
}
);
}
/**
* ************************************
* Get app settings
* ************************************
*
* @async
* @param {Object} config - The configuration object.
* @param {string} config.authToken - The authorization token to be used in the request header.
* @returns {Promise<AxiosResponse>} The response from the axios GET request.
*
*/
async getAppSettings(config) {
return this.axiosInstance.get("/settings", {
headers: {
Authorization: `Bearer ${config.authToken}`,
"Content-Type": "application/json",
},
});
}
}
export default NetworkService;