mirror of
https://github.com/BreizhHardware/Jellystat.git
synced 2026-01-18 16:27:20 +01:00
reworked frontend config handling to reduce api calls
This commit is contained in:
@@ -98,7 +98,7 @@ function App() {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
if (!newConfig.response) {
|
||||
setConfig(newConfig);
|
||||
} else {
|
||||
|
||||
@@ -1,20 +1,46 @@
|
||||
import axios from 'axios';
|
||||
import axios from "axios";
|
||||
|
||||
async function Config() {
|
||||
const token = localStorage.getItem('token');
|
||||
try {
|
||||
const response = await axios.get('/api/getconfig', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
const { JF_HOST, APP_USER,REQUIRE_LOGIN, settings, IS_JELLYFIN } = response.data;
|
||||
return { hostUrl: JF_HOST, username: APP_USER, token:token, requireLogin:REQUIRE_LOGIN, settings:settings, IS_JELLYFIN:IS_JELLYFIN };
|
||||
class Config {
|
||||
async fetchConfig() {
|
||||
const token = localStorage.getItem("token");
|
||||
try {
|
||||
const response = await axios.get("/api/getconfig", {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
const { JF_HOST, APP_USER, REQUIRE_LOGIN, settings, IS_JELLYFIN } = response.data;
|
||||
return {
|
||||
hostUrl: JF_HOST,
|
||||
username: APP_USER,
|
||||
token: token,
|
||||
requireLogin: REQUIRE_LOGIN,
|
||||
settings: settings,
|
||||
IS_JELLYFIN: IS_JELLYFIN,
|
||||
};
|
||||
} catch (error) {
|
||||
// console.log(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
// console.log(error);
|
||||
return error;
|
||||
async setConfig(config) {
|
||||
if (config == undefined) {
|
||||
config = await this.fetchConfig();
|
||||
}
|
||||
|
||||
localStorage.setItem("config", JSON.stringify(config));
|
||||
return config;
|
||||
}
|
||||
|
||||
async getConfig(refreshConfig) {
|
||||
let config = localStorage.getItem("config");
|
||||
if (config != undefined && !refreshConfig) {
|
||||
return JSON.parse(config);
|
||||
} else {
|
||||
return await this.setConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Config;
|
||||
export default new Config();
|
||||
|
||||
@@ -20,7 +20,7 @@ function Activity() {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_NETWORK") {
|
||||
@@ -116,7 +116,7 @@ function Activity() {
|
||||
</div>
|
||||
<FormControl
|
||||
type="text"
|
||||
placeholder= {i18next.t("SEARCH")}
|
||||
placeholder={i18next.t("SEARCH")}
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="ms-md-3 my-3 w-sm-100 w-md-75"
|
||||
|
||||
@@ -83,7 +83,7 @@ function ItemInfo() {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
@@ -226,7 +226,12 @@ function ItemInfo() {
|
||||
</h1>
|
||||
<Link
|
||||
className="px-2"
|
||||
to={config.hostUrl + `/web/index.html#!/${config.IS_JELLYFIN? "details" : "item"}?id=` + (data.EpisodeId || data.Id) + (config.settings.ServerID ? "&serverId=" + config.settings.ServerID : "")}
|
||||
to={
|
||||
config.hostUrl +
|
||||
`/web/index.html#!/${config.IS_JELLYFIN ? "details" : "item"}?id=` +
|
||||
(data.EpisodeId || data.Id) +
|
||||
(config.settings.ServerID ? "&serverId=" + config.settings.ServerID : "")
|
||||
}
|
||||
title={i18next.t("ITEM_INFO.OPEN_IN_JELLYFIN")}
|
||||
target="_blank"
|
||||
>
|
||||
|
||||
@@ -16,7 +16,7 @@ function MoreItems(props) {
|
||||
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
@@ -19,7 +19,7 @@ function LibraryLastWatched(props) {
|
||||
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
@@ -30,7 +30,7 @@ function LibraryItems(props) {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
@@ -62,7 +62,7 @@ function Sessions() {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function SettingsConfig() {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setuse_password(newConfig.requireLogin);
|
||||
setFormValues({ JS_USERNAME: newConfig.username });
|
||||
} catch (error) {
|
||||
@@ -84,6 +84,7 @@ export default function SettingsConfig() {
|
||||
}
|
||||
)
|
||||
.then((data) => {
|
||||
Config.setConfig();
|
||||
setuse_password(requireLogin);
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -126,6 +127,7 @@ export default function SettingsConfig() {
|
||||
// let result = await updatePassword(hashedOldPassword, hashedNewPassword);
|
||||
let result = await updateUser(username, hashedOldPassword, hashedNewPassword);
|
||||
|
||||
Config.setConfig();
|
||||
if (result.isValid) {
|
||||
setisSubmitted("Success");
|
||||
setsubmissionMessage(i18next.t("PASSWORD_UPDATE_SUCCESS"));
|
||||
|
||||
@@ -42,7 +42,7 @@ export default function SettingsConfig() {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
Config()
|
||||
Config.getConfig()
|
||||
.then((config) => {
|
||||
setFormValues({ JF_HOST: config.hostUrl });
|
||||
setConfig(config);
|
||||
@@ -94,6 +94,7 @@ export default function SettingsConfig() {
|
||||
setisSubmitted("Failed");
|
||||
setsubmissionMessage(`Error Updating Configuration: ${errorMessage}`);
|
||||
});
|
||||
Config.setConfig();
|
||||
}
|
||||
|
||||
function handleFormChange(event) {
|
||||
@@ -129,6 +130,7 @@ export default function SettingsConfig() {
|
||||
setisSubmitted("Failed");
|
||||
setsubmissionMessage("Error Updating Configuration: ", error);
|
||||
});
|
||||
Config.setConfig();
|
||||
}
|
||||
|
||||
function updateLanguage(event) {
|
||||
|
||||
@@ -17,7 +17,7 @@ function MostActiveUsers(props) {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_NETWORK") {
|
||||
|
||||
@@ -18,7 +18,7 @@ function MPMovies(props) {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_NETWORK") {
|
||||
|
||||
@@ -16,7 +16,7 @@ function MPMusic(props) {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_NETWORK") {
|
||||
|
||||
@@ -14,7 +14,7 @@ function MPSeries(props) {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_NETWORK") {
|
||||
|
||||
@@ -19,7 +19,7 @@ function MVMusic(props) {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_NETWORK") {
|
||||
|
||||
@@ -14,7 +14,7 @@ function MVMovies(props) {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_NETWORK") {
|
||||
|
||||
@@ -17,7 +17,7 @@ function MVSeries(props) {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_NETWORK") {
|
||||
|
||||
@@ -1,60 +1,58 @@
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useState, useEffect } from "react";
|
||||
import axios from "axios";
|
||||
import AccountCircleFillIcon from "remixicon-react/AccountCircleFillIcon";
|
||||
import Config from "../../lib/config";
|
||||
import {Tabs, Tab, Button, ButtonGroup } from 'react-bootstrap';
|
||||
import { Tabs, Tab, Button, ButtonGroup } from "react-bootstrap";
|
||||
|
||||
import GlobalStats from './user-info/globalStats';
|
||||
import LastPlayed from './user-info/lastplayed';
|
||||
import UserActivity from './user-info/user-activity';
|
||||
import GlobalStats from "./user-info/globalStats";
|
||||
import LastPlayed from "./user-info/lastplayed";
|
||||
import UserActivity from "./user-info/user-activity";
|
||||
import "../css/users/user-details.css";
|
||||
import { Trans } from 'react-i18next';
|
||||
|
||||
|
||||
|
||||
|
||||
import { Trans } from "react-i18next";
|
||||
|
||||
function UserInfo() {
|
||||
const { UserId } = useParams();
|
||||
const [data, setData] = useState();
|
||||
const [imgError, setImgError] = useState(false);
|
||||
const [config, setConfig] = useState();
|
||||
const [activeTab, setActiveTab] = useState('tabOverview');
|
||||
const [activeTab, setActiveTab] = useState("tabOverview");
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchData = async () => {
|
||||
if(config){
|
||||
try {
|
||||
const userData = await axios.post(`/api/getUserDetails`, {
|
||||
userid: UserId,
|
||||
}, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${config.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
setData(userData.data);
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const fetchData = async () => {
|
||||
if (config) {
|
||||
try {
|
||||
const userData = await axios.post(
|
||||
`/api/getUserDetails`,
|
||||
{
|
||||
userid: UserId,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${config.token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
setData(userData.data);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
fetchData();
|
||||
|
||||
if (!config) {
|
||||
fetchConfig();
|
||||
fetchConfig();
|
||||
}
|
||||
|
||||
const intervalId = setInterval(fetchData, 60000 * 5);
|
||||
@@ -69,48 +67,54 @@ function UserInfo() {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="user-detail-container">
|
||||
<div className="user-image-container">
|
||||
{imgError ? (
|
||||
<AccountCircleFillIcon size={"100%"} />
|
||||
) : (
|
||||
<img
|
||||
className="user-image"
|
||||
src={
|
||||
"/proxy/Users/Images/Primary?id=" +
|
||||
UserId+
|
||||
"&quality=100"
|
||||
}
|
||||
onError={handleImageError}
|
||||
alt=""
|
||||
></img>
|
||||
)}
|
||||
</div>
|
||||
<div className="user-image-container">
|
||||
{imgError ? (
|
||||
<AccountCircleFillIcon size={"100%"} />
|
||||
) : (
|
||||
<img
|
||||
className="user-image"
|
||||
src={"/proxy/Users/Images/Primary?id=" + UserId + "&quality=100"}
|
||||
onError={handleImageError}
|
||||
alt=""
|
||||
></img>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="user-name">{data.Name}</p>
|
||||
<div>
|
||||
<p className="user-name">{data.Name}</p>
|
||||
<ButtonGroup>
|
||||
<Button onClick={() => setActiveTab('tabOverview')} active={activeTab==='tabOverview'} variant='outline-primary' type='button'><Trans i18nKey="TAB_CONTROLS.OVERVIEW"/></Button>
|
||||
<Button onClick={() => setActiveTab('tabActivity')} active={activeTab==='tabActivity'} variant='outline-primary' type='button'><Trans i18nKey="TAB_CONTROLS.ACTIVITY"/></Button>
|
||||
<Button
|
||||
onClick={() => setActiveTab("tabOverview")}
|
||||
active={activeTab === "tabOverview"}
|
||||
variant="outline-primary"
|
||||
type="button"
|
||||
>
|
||||
<Trans i18nKey="TAB_CONTROLS.OVERVIEW" />
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => setActiveTab("tabActivity")}
|
||||
active={activeTab === "tabActivity"}
|
||||
variant="outline-primary"
|
||||
type="button"
|
||||
>
|
||||
<Trans i18nKey="TAB_CONTROLS.ACTIVITY" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<Tabs defaultActiveKey="tabOverview" activeKey={activeTab} variant='pills'>
|
||||
<Tab eventKey="tabOverview" className='bg-transparent'>
|
||||
<GlobalStats UserId={UserId}/>
|
||||
<LastPlayed UserId={UserId}/>
|
||||
</Tab>
|
||||
<Tab eventKey="tabActivity" className='bg-transparent'>
|
||||
<UserActivity UserId={UserId}/>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Tabs defaultActiveKey="tabOverview" activeKey={activeTab} variant="pills">
|
||||
<Tab eventKey="tabOverview" className="bg-transparent">
|
||||
<GlobalStats UserId={UserId} />
|
||||
<LastPlayed UserId={UserId} />
|
||||
</Tab>
|
||||
<Tab eventKey="tabActivity" className="bg-transparent">
|
||||
<UserActivity UserId={UserId} />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ function LastPlayed(props) {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
@@ -60,7 +60,7 @@ function Sessions() {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
@@ -21,7 +21,7 @@ function Libraries() {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_NETWORK") {
|
||||
|
||||
@@ -11,7 +11,6 @@ import InformationLineIcon from "remixicon-react/InformationLineIcon";
|
||||
import { Tooltip } from "@mui/material";
|
||||
import { Trans } from "react-i18next";
|
||||
|
||||
|
||||
function LibrarySelector() {
|
||||
const [data, setData] = useState();
|
||||
const [config, setConfig] = useState(null);
|
||||
@@ -19,7 +18,7 @@ function LibrarySelector() {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_NETWORK") {
|
||||
@@ -29,8 +28,7 @@ function LibrarySelector() {
|
||||
};
|
||||
|
||||
const fetchLibraries = () => {
|
||||
if(config)
|
||||
{
|
||||
if (config) {
|
||||
const url = `/api/TrackedLibraries`;
|
||||
axios
|
||||
.get(url, {
|
||||
@@ -45,11 +43,9 @@ function LibrarySelector() {
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
if (!config) {
|
||||
fetchConfig();
|
||||
}
|
||||
@@ -57,7 +53,7 @@ function LibrarySelector() {
|
||||
fetchLibraries();
|
||||
const intervalId = setInterval(fetchLibraries, 60000 * 60);
|
||||
return () => clearInterval(intervalId);
|
||||
}, [ config]);
|
||||
}, [config]);
|
||||
|
||||
if (!data) {
|
||||
return <Loading />;
|
||||
@@ -65,18 +61,24 @@ function LibrarySelector() {
|
||||
|
||||
return (
|
||||
<div className="libraries">
|
||||
<h1 className="py-4"><Trans i18nKey={"SETTINGS_PAGE.SELECT_LIBRARIES_TO_IMPORT"}/> <Tooltip title={<Trans i18nKey={"SETTINGS_PAGE.SELECT_LIBRARIES_TO_IMPORT_TOOLTIP"}/>}><span> <InformationLineIcon/></span></Tooltip></h1>
|
||||
<h1 className="py-4">
|
||||
<Trans i18nKey={"SETTINGS_PAGE.SELECT_LIBRARIES_TO_IMPORT"} />{" "}
|
||||
<Tooltip title={<Trans i18nKey={"SETTINGS_PAGE.SELECT_LIBRARIES_TO_IMPORT_TOOLTIP"} />}>
|
||||
<span>
|
||||
{" "}
|
||||
<InformationLineIcon />
|
||||
</span>
|
||||
</Tooltip>
|
||||
</h1>
|
||||
|
||||
<div xs={1} md={2} lg={4} className="g-0 libraries-container">
|
||||
{data &&
|
||||
{data &&
|
||||
data.map((item) => (
|
||||
<ErrorBoundary key={item.Id} >
|
||||
<SelectionCard data={item} base_url={config.hostUrl}/>
|
||||
</ErrorBoundary>
|
||||
|
||||
))}
|
||||
<ErrorBoundary key={item.Id}>
|
||||
<SelectionCard data={item} base_url={config.hostUrl} />
|
||||
</ErrorBoundary>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ function Login() {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_NETWORK") {
|
||||
|
||||
@@ -76,7 +76,7 @@ function Setup() {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_NETWORK") {
|
||||
|
||||
@@ -70,7 +70,7 @@ function Signup() {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_NETWORK") {
|
||||
|
||||
@@ -206,7 +206,11 @@ function Row(row) {
|
||||
<TableCell>{data.TotalPlays}</TableCell>
|
||||
<TableCell>{formatTotalWatchTime(data.TotalWatchTime) || `0 ${i18next.t("UNITS.MINUTES")}`}</TableCell>
|
||||
<TableCell style={{ textTransform: data.LastSeen ? "none" : "lowercase" }}>
|
||||
{data.LastSeen ? `${i18next.t("USERS_PAGE.AGO_ALT")} ${formatLastSeenTime(data.LastSeen)} ${i18next.t("USERS_PAGE.AGO").toLocaleLowerCase()}` : i18next.t("ERROR_MESSAGES.NEVER")}
|
||||
{data.LastSeen
|
||||
? `${i18next.t("USERS_PAGE.AGO_ALT")} ${formatLastSeenTime(data.LastSeen)} ${i18next
|
||||
.t("USERS_PAGE.AGO")
|
||||
.toLocaleLowerCase()}`
|
||||
: i18next.t("ERROR_MESSAGES.NEVER")}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
@@ -227,7 +231,7 @@ function Users() {
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const newConfig = await Config();
|
||||
const newConfig = await Config.getConfig();
|
||||
setConfig(newConfig);
|
||||
} catch (error) {
|
||||
if (error.code === "ERR_NETWORK") {
|
||||
@@ -431,7 +435,7 @@ function Users() {
|
||||
</div>
|
||||
<FormControl
|
||||
type="text"
|
||||
placeholder= {i18next.t("SEARCH")}
|
||||
placeholder={i18next.t("SEARCH")}
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="ms-md-3 my-3 w-sm-100 w-md-75"
|
||||
|
||||
Reference in New Issue
Block a user