mirror of
https://github.com/jambonz/jambonz-webapp.git
synced 2025-12-19 05:37:43 +00:00
UI improvement. (#521)
* don't remove service provider sid and filteredAccountSid when logout * support fetching applications with pagination * applications wip * support pagination for voip carriers * wip * support phone number pagination * wip * wip * wip * wip * wip * wip * wip * wip * wip
This commit is contained in:
@@ -92,10 +92,6 @@ export const DISABLE_ADDITIONAL_SPEECH_VENDORS: boolean =
|
|||||||
export const AWS_REGION: string =
|
export const AWS_REGION: string =
|
||||||
window.JAMBONZ?.AWS_REGION || import.meta.env.VITE_APP_AWS_REGION;
|
window.JAMBONZ?.AWS_REGION || import.meta.env.VITE_APP_AWS_REGION;
|
||||||
|
|
||||||
export const ENABLE_PHONE_NUMBER_LAZY_LOAD: boolean =
|
|
||||||
window.JAMBONZ?.ENABLE_PHONE_NUMBER_LAZY_LOAD === "true" ||
|
|
||||||
JSON.parse(import.meta.env.VITE_APP_ENABLE_PHONE_NUMBER_LAZY_LOAD || "false");
|
|
||||||
|
|
||||||
export const DEFAULT_SERVICE_PROVIDER_SID: string =
|
export const DEFAULT_SERVICE_PROVIDER_SID: string =
|
||||||
window.JAMBONZ?.DEFAULT_SERVICE_PROVIDER_SID ||
|
window.JAMBONZ?.DEFAULT_SERVICE_PROVIDER_SID ||
|
||||||
import.meta.env.VITE_APP_DEFAULT_SERVICE_PROVIDER_SID;
|
import.meta.env.VITE_APP_DEFAULT_SERVICE_PROVIDER_SID;
|
||||||
|
|||||||
@@ -97,6 +97,8 @@ import type {
|
|||||||
SpeechSupportedLanguagesAndVoices,
|
SpeechSupportedLanguagesAndVoices,
|
||||||
AppEnv,
|
AppEnv,
|
||||||
PhoneNumberQuery,
|
PhoneNumberQuery,
|
||||||
|
ApplicationQuery,
|
||||||
|
VoipCarrierQuery,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import { Availability, StatusCodes } from "./types";
|
import { Availability, StatusCodes } from "./types";
|
||||||
import { JaegerRoot } from "./jaeger-types";
|
import { JaegerRoot } from "./jaeger-types";
|
||||||
@@ -821,6 +823,28 @@ export const getAppEnvSchema = (url: string) => {
|
|||||||
return getFetch<AppEnv>(`${API_APP_ENV}?url=${url}`);
|
return getFetch<AppEnv>(`${API_APP_ENV}?url=${url}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getApplications = (
|
||||||
|
sid: string,
|
||||||
|
query: Partial<ApplicationQuery>,
|
||||||
|
) => {
|
||||||
|
const qryStr = getQuery<Partial<ApplicationQuery>>(query);
|
||||||
|
|
||||||
|
return getFetch<PagedResponse<Application>>(
|
||||||
|
`${API_ACCOUNTS}/${sid}/Applications?${qryStr}`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getSPVoipCarriers = (
|
||||||
|
sid: string,
|
||||||
|
query: Partial<VoipCarrierQuery>,
|
||||||
|
) => {
|
||||||
|
const qryStr = getQuery<Partial<VoipCarrierQuery>>(query);
|
||||||
|
|
||||||
|
return getFetch<PagedResponse<Carrier>>(
|
||||||
|
`${API_SERVICE_PROVIDERS}/${sid}/VoipCarriers?${qryStr}`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
/** Wrappers for APIs that can have a mock dev server response */
|
/** Wrappers for APIs that can have a mock dev server response */
|
||||||
|
|
||||||
export const getMe = () => {
|
export const getMe = () => {
|
||||||
@@ -903,7 +927,7 @@ export const getPrice = () => {
|
|||||||
export const getPhoneNumbers = (query: Partial<PhoneNumberQuery>) => {
|
export const getPhoneNumbers = (query: Partial<PhoneNumberQuery>) => {
|
||||||
const qryStr = getQuery<Partial<PhoneNumberQuery>>(query);
|
const qryStr = getQuery<Partial<PhoneNumberQuery>>(query);
|
||||||
|
|
||||||
return getFetch<PhoneNumber[]>(`${API_PHONE_NUMBERS}?${qryStr}`);
|
return getFetch<PagedResponse<PhoneNumber>>(`${API_PHONE_NUMBERS}?${qryStr}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getSpeechSupportedLanguagesAndVoices = (
|
export const getSpeechSupportedLanguagesAndVoices = (
|
||||||
|
|||||||
@@ -557,12 +557,14 @@ export interface Client {
|
|||||||
|
|
||||||
export interface PageQuery {
|
export interface PageQuery {
|
||||||
page: number;
|
page: number;
|
||||||
|
page_size?: number;
|
||||||
count: number;
|
count: number;
|
||||||
start?: string;
|
start?: string;
|
||||||
days?: number;
|
days?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PhoneNumberQuery extends PageQuery {
|
export interface PhoneNumberQuery extends PageQuery {
|
||||||
|
service_provider_sid?: string;
|
||||||
account_sid?: string;
|
account_sid?: string;
|
||||||
filter?: string;
|
filter?: string;
|
||||||
}
|
}
|
||||||
@@ -572,6 +574,15 @@ export interface CallQuery extends PageQuery {
|
|||||||
answered?: string;
|
answered?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ApplicationQuery extends PageQuery {
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VoipCarrierQuery extends PageQuery {
|
||||||
|
name?: string;
|
||||||
|
account_sid?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface GoogleCustomVoicesQuery {
|
export interface GoogleCustomVoicesQuery {
|
||||||
speech_credential_sid?: string;
|
speech_credential_sid?: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
|
|||||||
@@ -11,7 +11,11 @@ import {
|
|||||||
toastSuccess,
|
toastSuccess,
|
||||||
toastError,
|
toastError,
|
||||||
} from "src/store";
|
} from "src/store";
|
||||||
import { getActiveSP, setActiveSP } from "src/store/localStore";
|
import {
|
||||||
|
getActiveSP,
|
||||||
|
removeAccountFilter,
|
||||||
|
setActiveSP,
|
||||||
|
} from "src/store/localStore";
|
||||||
import { postServiceProviders } from "src/api";
|
import { postServiceProviders } from "src/api";
|
||||||
|
|
||||||
import type { NaviItem } from "./items";
|
import type { NaviItem } from "./items";
|
||||||
@@ -166,6 +170,7 @@ export const Navi = ({
|
|||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setSid(e.target.value);
|
setSid(e.target.value);
|
||||||
setActiveSP(e.target.value);
|
setActiveSP(e.target.value);
|
||||||
|
removeAccountFilter();
|
||||||
navigate(ROUTE_LOGIN);
|
navigate(ROUTE_LOGIN);
|
||||||
}}
|
}}
|
||||||
disabled={user?.scope !== USER_ADMIN}
|
disabled={user?.scope !== USER_ADMIN}
|
||||||
|
|||||||
@@ -68,10 +68,10 @@ export const Alerts = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useMemo(() => {
|
useMemo(() => {
|
||||||
|
setAccountSid(getAccountFilter() || accountSid);
|
||||||
|
if (!accountSid && user?.account_sid) setAccountSid(user?.account_sid);
|
||||||
if (getQueryFilter()) {
|
if (getQueryFilter()) {
|
||||||
const [date] = getQueryFilter().split("/");
|
const [date] = getQueryFilter().split("/");
|
||||||
setAccountSid(getAccountFilter() || accountSid);
|
|
||||||
if (!accountSid && user?.account_sid) setAccountSid(user?.account_sid);
|
|
||||||
setDateFilter(date);
|
setDateFilter(date);
|
||||||
}
|
}
|
||||||
}, [accountSid]);
|
}, [accountSid]);
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState, useRef } from "react";
|
||||||
import { H1, M, Button, Icon } from "@jambonz/ui-kit";
|
import { H1, M, Button, Icon, ButtonGroup, MS } from "@jambonz/ui-kit";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
import { deleteApplication, useServiceProviderData, useApiData } from "src/api";
|
import {
|
||||||
|
deleteApplication,
|
||||||
|
useServiceProviderData,
|
||||||
|
getApplications,
|
||||||
|
} from "src/api";
|
||||||
import {
|
import {
|
||||||
ROUTE_INTERNAL_APPLICATIONS,
|
ROUTE_INTERNAL_APPLICATIONS,
|
||||||
ROUTE_INTERNAL_ACCOUNTS,
|
ROUTE_INTERNAL_ACCOUNTS,
|
||||||
@@ -13,20 +17,17 @@ import {
|
|||||||
Spinner,
|
Spinner,
|
||||||
AccountFilter,
|
AccountFilter,
|
||||||
SearchFilter,
|
SearchFilter,
|
||||||
|
Pagination,
|
||||||
|
SelectFilter,
|
||||||
} from "src/components";
|
} from "src/components";
|
||||||
import { DeleteApplication } from "./delete";
|
import { DeleteApplication } from "./delete";
|
||||||
import { toastError, toastSuccess, useSelectState } from "src/store";
|
import { toastError, toastSuccess, useSelectState } from "src/store";
|
||||||
import {
|
import { isUserAccountScope, hasLength, hasValue } from "src/utils";
|
||||||
isUserAccountScope,
|
|
||||||
hasLength,
|
|
||||||
hasValue,
|
|
||||||
useFilteredResults,
|
|
||||||
} from "src/utils";
|
|
||||||
|
|
||||||
import type { Application, Account } from "src/api/types";
|
import type { Application, Account } from "src/api/types";
|
||||||
import { ScopedAccess } from "src/components/scoped-access";
|
import { ScopedAccess } from "src/components/scoped-access";
|
||||||
import { Scope } from "src/store/types";
|
import { Scope } from "src/store/types";
|
||||||
import { USER_ACCOUNT } from "src/api/constants";
|
import { PER_PAGE_SELECTION, USER_ACCOUNT } from "src/api/constants";
|
||||||
import { getAccountFilter, setLocation } from "src/store/localStore";
|
import { getAccountFilter, setLocation } from "src/store/localStore";
|
||||||
|
|
||||||
export const Applications = () => {
|
export const Applications = () => {
|
||||||
@@ -34,14 +35,51 @@ export const Applications = () => {
|
|||||||
const [accounts] = useServiceProviderData<Account[]>("Accounts");
|
const [accounts] = useServiceProviderData<Account[]>("Accounts");
|
||||||
const [accountSid, setAccountSid] = useState("");
|
const [accountSid, setAccountSid] = useState("");
|
||||||
const [application, setApplication] = useState<Application | null>(null);
|
const [application, setApplication] = useState<Application | null>(null);
|
||||||
const [apiUrl, setApiUrl] = useState("");
|
const [applications, setApplications] = useState<Application[] | null>(null);
|
||||||
const [applications, refetch] = useApiData<Application[]>(apiUrl);
|
|
||||||
const [filter, setFilter] = useState("");
|
const [filter, setFilter] = useState("");
|
||||||
|
|
||||||
const filteredApplications = useFilteredResults<Application>(
|
const [applicationsTotal, setApplicationsTotal] = useState(0);
|
||||||
filter,
|
const [pageNumber, setPageNumber] = useState(1);
|
||||||
applications,
|
const [perPageFilter, setPerPageFilter] = useState("25");
|
||||||
);
|
const [maxPageNumber, setMaxPageNumber] = useState(1);
|
||||||
|
|
||||||
|
// Track previous values to detect changes
|
||||||
|
const prevValuesRef = useRef({
|
||||||
|
accountSid: "",
|
||||||
|
filter: "",
|
||||||
|
pageNumber: 1,
|
||||||
|
perPageFilter: "25",
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchApplications = (resetPage = false) => {
|
||||||
|
// Don't fetch if no account is selected
|
||||||
|
if (!accountSid) return;
|
||||||
|
|
||||||
|
setApplications(null);
|
||||||
|
|
||||||
|
// Calculate the correct page to use
|
||||||
|
const currentPage = resetPage ? 1 : pageNumber;
|
||||||
|
|
||||||
|
// If we're resetting the page, also update the state
|
||||||
|
if (resetPage && pageNumber !== 1) {
|
||||||
|
setPageNumber(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
getApplications(accountSid, {
|
||||||
|
page: currentPage,
|
||||||
|
page_size: Number(perPageFilter),
|
||||||
|
...(filter && { name: filter }),
|
||||||
|
})
|
||||||
|
.then(({ json }) => {
|
||||||
|
setApplications(json.data);
|
||||||
|
setApplicationsTotal(json.total);
|
||||||
|
setMaxPageNumber(Math.ceil(json.total / Number(perPageFilter)));
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setApplications([]);
|
||||||
|
toastError(error.msg);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
if (application) {
|
if (application) {
|
||||||
@@ -53,8 +91,7 @@ export const Applications = () => {
|
|||||||
}
|
}
|
||||||
deleteApplication(application.application_sid)
|
deleteApplication(application.application_sid)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// getApplications();
|
fetchApplications(false);
|
||||||
refetch();
|
|
||||||
setApplication(null);
|
setApplication(null);
|
||||||
toastSuccess(
|
toastSuccess(
|
||||||
<>
|
<>
|
||||||
@@ -68,18 +105,44 @@ export const Applications = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Set initial account
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLocation();
|
|
||||||
if (user?.account_sid && user.scope === USER_ACCOUNT) {
|
if (user?.account_sid && user.scope === USER_ACCOUNT) {
|
||||||
setAccountSid(user?.account_sid);
|
setAccountSid(user?.account_sid);
|
||||||
} else {
|
} else {
|
||||||
setAccountSid(getAccountFilter() || accountSid);
|
setAccountSid(
|
||||||
|
getAccountFilter() || accountSid || accounts?.[0]?.account_sid || "",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
setLocation();
|
||||||
|
}, [user, accounts]);
|
||||||
|
|
||||||
if (accountSid) {
|
// This single effect handles all data fetching triggers
|
||||||
setApiUrl(`Accounts/${accountSid}/Applications`);
|
useEffect(() => {
|
||||||
}
|
const accSid = accountSid || getAccountFilter() || "";
|
||||||
}, [accountSid, user]);
|
|
||||||
|
if (!accSid) return;
|
||||||
|
|
||||||
|
// Determine if the change requires a page reset
|
||||||
|
const prevValues = prevValuesRef.current;
|
||||||
|
const isFilterChange =
|
||||||
|
prevValues.accountSid !== accountSid || prevValues.filter !== filter;
|
||||||
|
|
||||||
|
const isPageSizeChange =
|
||||||
|
prevValues.perPageFilter !== perPageFilter &&
|
||||||
|
prevValues.perPageFilter !== ""; // Skip initial render
|
||||||
|
|
||||||
|
// Update ref with current values for next comparison
|
||||||
|
prevValuesRef.current = {
|
||||||
|
accountSid: accSid,
|
||||||
|
filter,
|
||||||
|
pageNumber,
|
||||||
|
perPageFilter,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch data with page reset if needed
|
||||||
|
fetchApplications(isFilterChange || isPageSizeChange);
|
||||||
|
}, [accountSid, filter, pageNumber, perPageFilter]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -100,6 +163,7 @@ export const Applications = () => {
|
|||||||
<SearchFilter
|
<SearchFilter
|
||||||
placeholder="Filter applications"
|
placeholder="Filter applications"
|
||||||
filter={[filter, setFilter]}
|
filter={[filter, setFilter]}
|
||||||
|
delay={1000}
|
||||||
/>
|
/>
|
||||||
<ScopedAccess user={user} scope={Scope.service_provider}>
|
<ScopedAccess user={user} scope={Scope.service_provider}>
|
||||||
<AccountFilter
|
<AccountFilter
|
||||||
@@ -108,12 +172,12 @@ export const Applications = () => {
|
|||||||
/>
|
/>
|
||||||
</ScopedAccess>
|
</ScopedAccess>
|
||||||
</section>
|
</section>
|
||||||
<Section {...(hasLength(filteredApplications) && { slim: true })}>
|
<Section {...(hasLength(applications) && { slim: true })}>
|
||||||
<div className="list">
|
<div className="list">
|
||||||
{!hasValue(applications) && hasLength(accounts) ? (
|
{!hasValue(applications) && hasLength(accounts) ? (
|
||||||
<Spinner />
|
<Spinner />
|
||||||
) : hasLength(filteredApplications) ? (
|
) : hasLength(applications) ? (
|
||||||
filteredApplications
|
applications
|
||||||
.sort((a, b) => a.name.localeCompare(b.name))
|
.sort((a, b) => a.name.localeCompare(b.name))
|
||||||
.map((application) => {
|
.map((application) => {
|
||||||
return (
|
return (
|
||||||
@@ -189,6 +253,26 @@ export const Applications = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Section>
|
</Section>
|
||||||
)}
|
)}
|
||||||
|
<footer>
|
||||||
|
<ButtonGroup>
|
||||||
|
<MS>
|
||||||
|
Total: {applicationsTotal} record
|
||||||
|
{applicationsTotal === 1 ? "" : "s"}
|
||||||
|
</MS>
|
||||||
|
{hasLength(applications) && (
|
||||||
|
<Pagination
|
||||||
|
pageNumber={pageNumber}
|
||||||
|
setPageNumber={setPageNumber}
|
||||||
|
maxPageNumber={maxPageNumber}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<SelectFilter
|
||||||
|
id="page_filter"
|
||||||
|
filter={[perPageFilter, setPerPageFilter]}
|
||||||
|
options={PER_PAGE_SELECTION}
|
||||||
|
/>
|
||||||
|
</ButtonGroup>
|
||||||
|
</footer>
|
||||||
{application && (
|
{application && (
|
||||||
<DeleteApplication
|
<DeleteApplication
|
||||||
application={application}
|
application={application}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import React, { useState, useMemo, useEffect } from "react";
|
import React, { useState, useEffect, useRef } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { Button, H1, Icon, M } from "@jambonz/ui-kit";
|
import { Button, ButtonGroup, H1, Icon, M, MS } from "@jambonz/ui-kit";
|
||||||
import {
|
import {
|
||||||
deleteCarrier,
|
deleteCarrier,
|
||||||
deleteSipGateway,
|
deleteSipGateway,
|
||||||
deleteSmppGateway,
|
deleteSmppGateway,
|
||||||
getFetch,
|
getFetch,
|
||||||
|
getSPVoipCarriers,
|
||||||
useApiData,
|
useApiData,
|
||||||
useServiceProviderData,
|
useServiceProviderData,
|
||||||
} from "src/api";
|
} from "src/api";
|
||||||
@@ -17,20 +18,18 @@ import {
|
|||||||
Section,
|
Section,
|
||||||
Spinner,
|
Spinner,
|
||||||
SearchFilter,
|
SearchFilter,
|
||||||
|
Pagination,
|
||||||
|
SelectFilter,
|
||||||
} from "src/components";
|
} from "src/components";
|
||||||
import { ScopedAccess } from "src/components/scoped-access";
|
import { ScopedAccess } from "src/components/scoped-access";
|
||||||
import { Gateways } from "./gateways";
|
import { Gateways } from "./gateways";
|
||||||
import {
|
import { isUserAccountScope, hasLength, hasValue } from "src/utils";
|
||||||
isUserAccountScope,
|
|
||||||
hasLength,
|
|
||||||
hasValue,
|
|
||||||
useFilteredResults,
|
|
||||||
} from "src/utils";
|
|
||||||
import {
|
import {
|
||||||
API_SIP_GATEWAY,
|
API_SIP_GATEWAY,
|
||||||
API_SMPP_GATEWAY,
|
API_SMPP_GATEWAY,
|
||||||
CARRIER_REG_OK,
|
CARRIER_REG_OK,
|
||||||
ENABLE_HOSTED_SYSTEM,
|
ENABLE_HOSTED_SYSTEM,
|
||||||
|
PER_PAGE_SELECTION,
|
||||||
USER_ACCOUNT,
|
USER_ACCOUNT,
|
||||||
} from "src/api/constants";
|
} from "src/api/constants";
|
||||||
import { DeleteCarrier } from "./delete";
|
import { DeleteCarrier } from "./delete";
|
||||||
@@ -49,32 +48,55 @@ export const Carriers = () => {
|
|||||||
const user = useSelectState("user");
|
const user = useSelectState("user");
|
||||||
const [userData] = useApiData<CurrentUserData>("Users/me");
|
const [userData] = useApiData<CurrentUserData>("Users/me");
|
||||||
const currentServiceProvider = useSelectState("currentServiceProvider");
|
const currentServiceProvider = useSelectState("currentServiceProvider");
|
||||||
const [apiUrl, setApiUrl] = useState("");
|
|
||||||
const [carrier, setCarrier] = useState<Carrier | null>(null);
|
const [carrier, setCarrier] = useState<Carrier | null>(null);
|
||||||
const [carriers, refetch] = useApiData<Carrier[]>(apiUrl);
|
const [carriers, setCarriers] = useState<Carrier[] | null>(null);
|
||||||
const [accounts] = useServiceProviderData<Account[]>("Accounts");
|
const [accounts] = useServiceProviderData<Account[]>("Accounts");
|
||||||
const [accountSid, setAccountSid] = useState("");
|
const [accountSid, setAccountSid] = useState("");
|
||||||
const [filter, setFilter] = useState("");
|
const [filter, setFilter] = useState("");
|
||||||
|
|
||||||
const carriersFiltered = useMemo(() => {
|
const [carriersTotal, setCarriersTotal] = useState(0);
|
||||||
setAccountSid(getAccountFilter());
|
const [pageNumber, setPageNumber] = useState(1);
|
||||||
if (user?.account_sid && user?.scope === USER_ACCOUNT) {
|
const [perPageFilter, setPerPageFilter] = useState("25");
|
||||||
setAccountSid(user?.account_sid);
|
const [maxPageNumber, setMaxPageNumber] = useState(1);
|
||||||
|
|
||||||
|
// Add a ref to track previous values
|
||||||
|
const prevValuesRef = useRef({
|
||||||
|
serviceProviderId: "",
|
||||||
|
accountSid: "",
|
||||||
|
filter: "",
|
||||||
|
pageNumber: 1,
|
||||||
|
perPageFilter: "25",
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchCarriers = (resetPage = false) => {
|
||||||
|
if (!currentServiceProvider) return;
|
||||||
|
|
||||||
|
setCarriers(null);
|
||||||
|
|
||||||
|
// Calculate the correct page to use
|
||||||
|
const currentPage = resetPage ? 1 : pageNumber;
|
||||||
|
|
||||||
|
// If we're resetting the page, also update the state
|
||||||
|
if (resetPage && pageNumber !== 1) {
|
||||||
|
setPageNumber(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return carriers
|
getSPVoipCarriers(currentServiceProvider.service_provider_sid, {
|
||||||
? carriers.filter((carrier) =>
|
page: currentPage,
|
||||||
accountSid
|
page_size: Number(perPageFilter),
|
||||||
? carrier.account_sid === accountSid
|
...(filter && { name: filter }),
|
||||||
: carrier.account_sid === null,
|
...(accountSid && { account_sid: accountSid }),
|
||||||
)
|
})
|
||||||
: [];
|
.then(({ json }) => {
|
||||||
}, [accountSid, carrier, carriers]);
|
setCarriers(json.data);
|
||||||
|
setCarriersTotal(json.total);
|
||||||
const filteredCarriers = useFilteredResults<Carrier>(
|
setMaxPageNumber(Math.ceil(json.total / Number(perPageFilter)));
|
||||||
filter,
|
})
|
||||||
carriersFiltered,
|
.catch((error) => {
|
||||||
);
|
setCarriers([]);
|
||||||
|
toastError(error.msg);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
if (carrier) {
|
if (carrier) {
|
||||||
@@ -113,7 +135,7 @@ export const Carriers = () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
setCarrier(null);
|
setCarrier(null);
|
||||||
refetch();
|
fetchCarriers(false);
|
||||||
toastSuccess(
|
toastSuccess(
|
||||||
<>
|
<>
|
||||||
Deleted Carrier <strong>{carrier.name}</strong>
|
Deleted Carrier <strong>{carrier.name}</strong>
|
||||||
@@ -126,14 +148,45 @@ export const Carriers = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Initial account setup
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLocation();
|
if (user?.account_sid && user?.scope === USER_ACCOUNT) {
|
||||||
if (currentServiceProvider) {
|
setAccountSid(user?.account_sid);
|
||||||
setApiUrl(
|
} else {
|
||||||
`ServiceProviders/${currentServiceProvider.service_provider_sid}/VoipCarriers`,
|
setAccountSid(getAccountFilter());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}, [user, currentServiceProvider, accountSid]);
|
setLocation();
|
||||||
|
}, [user, accounts]);
|
||||||
|
|
||||||
|
// Combined effect for all data fetching
|
||||||
|
useEffect(() => {
|
||||||
|
if (!currentServiceProvider) return;
|
||||||
|
|
||||||
|
const prevValues = prevValuesRef.current;
|
||||||
|
const currentSPId = currentServiceProvider.service_provider_sid;
|
||||||
|
|
||||||
|
// Determine if we should reset pagination
|
||||||
|
const isFilterOrProviderChange =
|
||||||
|
prevValues.serviceProviderId !== currentSPId ||
|
||||||
|
prevValues.accountSid !== accountSid ||
|
||||||
|
prevValues.filter !== filter;
|
||||||
|
|
||||||
|
const isPageSizeChange =
|
||||||
|
prevValues.perPageFilter !== perPageFilter &&
|
||||||
|
prevValues.perPageFilter !== "25"; // Skip initial render
|
||||||
|
|
||||||
|
// Update ref for next comparison
|
||||||
|
prevValuesRef.current = {
|
||||||
|
serviceProviderId: currentSPId,
|
||||||
|
accountSid,
|
||||||
|
filter,
|
||||||
|
pageNumber,
|
||||||
|
perPageFilter,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch data with page reset if filters changed
|
||||||
|
fetchCarriers(isFilterOrProviderChange || isPageSizeChange);
|
||||||
|
}, [currentServiceProvider, accountSid, filter, pageNumber, perPageFilter]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -159,6 +212,7 @@ export const Carriers = () => {
|
|||||||
<SearchFilter
|
<SearchFilter
|
||||||
placeholder="Filter carriers"
|
placeholder="Filter carriers"
|
||||||
filter={[filter, setFilter]}
|
filter={[filter, setFilter]}
|
||||||
|
delay={1000}
|
||||||
/>
|
/>
|
||||||
<ScopedAccess user={user} scope={Scope.service_provider}>
|
<ScopedAccess user={user} scope={Scope.service_provider}>
|
||||||
<AccountFilter
|
<AccountFilter
|
||||||
@@ -169,12 +223,12 @@ export const Carriers = () => {
|
|||||||
/>
|
/>
|
||||||
</ScopedAccess>
|
</ScopedAccess>
|
||||||
</section>
|
</section>
|
||||||
<Section {...(hasLength(filteredCarriers) && { slim: true })}>
|
<Section {...(hasLength(carriers) && { slim: true })}>
|
||||||
<div className="list">
|
<div className="list">
|
||||||
{!hasValue(carriers) && hasLength(accounts) ? (
|
{!hasValue(carriers) && hasLength(accounts) ? (
|
||||||
<Spinner />
|
<Spinner />
|
||||||
) : hasLength(filteredCarriers) ? (
|
) : hasLength(carriers) ? (
|
||||||
filteredCarriers.map((carrier) => (
|
carriers.map((carrier) => (
|
||||||
<div className="item" key={carrier.voip_carrier_sid}>
|
<div className="item" key={carrier.voip_carrier_sid}>
|
||||||
<div className="item__info">
|
<div className="item__info">
|
||||||
<div className="item__title">
|
<div className="item__title">
|
||||||
@@ -274,6 +328,26 @@ export const Carriers = () => {
|
|||||||
Add carrier
|
Add carrier
|
||||||
</Button>
|
</Button>
|
||||||
</Section>
|
</Section>
|
||||||
|
<footer>
|
||||||
|
<ButtonGroup>
|
||||||
|
<MS>
|
||||||
|
Total: {carriersTotal} record
|
||||||
|
{carriersTotal === 1 ? "" : "s"}
|
||||||
|
</MS>
|
||||||
|
{hasLength(carriers) && (
|
||||||
|
<Pagination
|
||||||
|
pageNumber={pageNumber}
|
||||||
|
setPageNumber={setPageNumber}
|
||||||
|
maxPageNumber={maxPageNumber}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<SelectFilter
|
||||||
|
id="page_filter"
|
||||||
|
filter={[perPageFilter, setPerPageFilter]}
|
||||||
|
options={PER_PAGE_SELECTION}
|
||||||
|
/>
|
||||||
|
</ButtonGroup>
|
||||||
|
</footer>
|
||||||
{carrier && (
|
{carrier && (
|
||||||
<DeleteCarrier
|
<DeleteCarrier
|
||||||
carrier={carrier}
|
carrier={carrier}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { Scope } from "src/store/types";
|
|||||||
import { hasLength, hasValue, useFilteredResults } from "src/utils";
|
import { hasLength, hasValue, useFilteredResults } from "src/utils";
|
||||||
import ClientsDelete from "./delete";
|
import ClientsDelete from "./delete";
|
||||||
import { USER_ACCOUNT } from "src/api/constants";
|
import { USER_ACCOUNT } from "src/api/constants";
|
||||||
|
import { getAccountFilter } from "src/store/localStore";
|
||||||
|
|
||||||
export const Clients = () => {
|
export const Clients = () => {
|
||||||
const user = useSelectState("user");
|
const user = useSelectState("user");
|
||||||
@@ -32,6 +33,7 @@ export const Clients = () => {
|
|||||||
const [client, setClient] = useState<Client | null>();
|
const [client, setClient] = useState<Client | null>();
|
||||||
|
|
||||||
const tmpFilteredClients = useMemo(() => {
|
const tmpFilteredClients = useMemo(() => {
|
||||||
|
setAccountSid(getAccountFilter() || accountSid);
|
||||||
if (user?.account_sid && user?.scope === USER_ACCOUNT) {
|
if (user?.account_sid && user?.scope === USER_ACCOUNT) {
|
||||||
setAccountSid(user?.account_sid);
|
setAccountSid(user?.account_sid);
|
||||||
return clients;
|
return clients;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useMemo, useState } from "react";
|
import React, { useEffect, useState, useRef } from "react";
|
||||||
import { Button, ButtonGroup, H1, Icon, MS } from "@jambonz/ui-kit";
|
import { Button, ButtonGroup, H1, Icon, MS } from "@jambonz/ui-kit";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
@@ -16,28 +16,26 @@ import {
|
|||||||
ApplicationFilter,
|
ApplicationFilter,
|
||||||
SearchFilter,
|
SearchFilter,
|
||||||
AccountFilter,
|
AccountFilter,
|
||||||
|
Pagination,
|
||||||
|
SelectFilter,
|
||||||
} from "src/components";
|
} from "src/components";
|
||||||
import {
|
import {
|
||||||
ROUTE_INTERNAL_ACCOUNTS,
|
ROUTE_INTERNAL_ACCOUNTS,
|
||||||
ROUTE_INTERNAL_CARRIERS,
|
ROUTE_INTERNAL_CARRIERS,
|
||||||
ROUTE_INTERNAL_PHONE_NUMBERS,
|
ROUTE_INTERNAL_PHONE_NUMBERS,
|
||||||
} from "src/router/routes";
|
} from "src/router/routes";
|
||||||
import {
|
import { hasLength, hasValue, formatPhoneNumber } from "src/utils";
|
||||||
hasLength,
|
|
||||||
hasValue,
|
|
||||||
formatPhoneNumber,
|
|
||||||
useFilteredResults,
|
|
||||||
} from "src/utils";
|
|
||||||
import { DeletePhoneNumber } from "./delete";
|
import { DeletePhoneNumber } from "./delete";
|
||||||
|
|
||||||
import type { Account, PhoneNumber, Carrier, Application } from "src/api/types";
|
import type { Account, PhoneNumber, Carrier, Application } from "src/api/types";
|
||||||
import { ENABLE_PHONE_NUMBER_LAZY_LOAD, USER_ACCOUNT } from "src/api/constants";
|
import { PER_PAGE_SELECTION, USER_ACCOUNT } from "src/api/constants";
|
||||||
import { ScopedAccess } from "src/components/scoped-access";
|
import { ScopedAccess } from "src/components/scoped-access";
|
||||||
import { Scope } from "src/store/types";
|
import { Scope } from "src/store/types";
|
||||||
import { getAccountFilter, setLocation } from "src/store/localStore";
|
import { getAccountFilter, setLocation } from "src/store/localStore";
|
||||||
|
|
||||||
export const PhoneNumbers = () => {
|
export const PhoneNumbers = () => {
|
||||||
const user = useSelectState("user");
|
const user = useSelectState("user");
|
||||||
|
const currentServiceProvider = useSelectState("currentServiceProvider");
|
||||||
const [accounts] = useServiceProviderData<Account[]>("Accounts");
|
const [accounts] = useServiceProviderData<Account[]>("Accounts");
|
||||||
const [applications] = useServiceProviderData<Application[]>("Applications");
|
const [applications] = useServiceProviderData<Application[]>("Applications");
|
||||||
const [carriers] = useServiceProviderData<Carrier[]>("VoipCarriers");
|
const [carriers] = useServiceProviderData<Carrier[]>("VoipCarriers");
|
||||||
@@ -51,35 +49,48 @@ export const PhoneNumbers = () => {
|
|||||||
const [applyMassEdit, setApplyMassEdit] = useState(false);
|
const [applyMassEdit, setApplyMassEdit] = useState(false);
|
||||||
const [filter, setFilter] = useState("");
|
const [filter, setFilter] = useState("");
|
||||||
const [accountSid, setAccountSid] = useState("");
|
const [accountSid, setAccountSid] = useState("");
|
||||||
|
const [phoneNumbersTotal, setphoneNumbersTotal] = useState(0);
|
||||||
|
const [pageNumber, setPageNumber] = useState(1);
|
||||||
|
const [perPageFilter, setPerPageFilter] = useState("25");
|
||||||
|
const [maxPageNumber, setMaxPageNumber] = useState(1);
|
||||||
|
|
||||||
const phoneNumbersFiltered = useMemo(() => {
|
// Add ref to track previous values
|
||||||
setAccountSid(getAccountFilter());
|
const prevValuesRef = useRef({
|
||||||
return phoneNumbers
|
serviceProviderId: "",
|
||||||
? phoneNumbers.filter(
|
accountSid: "",
|
||||||
(phn) => !accountSid || phn.account_sid === accountSid,
|
filter: "",
|
||||||
)
|
pageNumber: 1,
|
||||||
: [];
|
perPageFilter: "25",
|
||||||
}, [phoneNumbers, ...[!ENABLE_PHONE_NUMBER_LAZY_LOAD && accountSid]]);
|
});
|
||||||
|
|
||||||
const filteredPhoneNumbers = !ENABLE_PHONE_NUMBER_LAZY_LOAD
|
const fetchPhoneNumbers = (resetPage = false) => {
|
||||||
? useFilteredResults<PhoneNumber>(filter, phoneNumbersFiltered)
|
setPhoneNumbers(null);
|
||||||
: phoneNumbersFiltered;
|
|
||||||
|
|
||||||
const refetch = () => {
|
// Calculate the correct page to use
|
||||||
getPhoneNumbers(
|
const currentPage = resetPage ? 1 : pageNumber;
|
||||||
!ENABLE_PHONE_NUMBER_LAZY_LOAD
|
|
||||||
? {}
|
// If we're resetting the page, also update the state
|
||||||
: {
|
if (resetPage && pageNumber !== 1) {
|
||||||
...(accountSid && { account_sid: accountSid }),
|
setPageNumber(1);
|
||||||
...(filter && { filter }),
|
}
|
||||||
},
|
|
||||||
)
|
const accSid = accountSid || getAccountFilter() || "";
|
||||||
|
|
||||||
|
getPhoneNumbers({
|
||||||
|
page: currentPage,
|
||||||
|
page_size: Number(perPageFilter),
|
||||||
|
...(accSid && { account_sid: accSid }),
|
||||||
|
...(filter && { filter }),
|
||||||
|
})
|
||||||
.then(({ json }) => {
|
.then(({ json }) => {
|
||||||
if (json) {
|
if (json) {
|
||||||
setPhoneNumbers(json);
|
setPhoneNumbers(json.data);
|
||||||
|
setphoneNumbersTotal(json.total);
|
||||||
|
setMaxPageNumber(Math.ceil(json.total / Number(perPageFilter)));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
setPhoneNumbers([]);
|
||||||
toastError(error.msg);
|
toastError(error.msg);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -95,9 +106,11 @@ export const PhoneNumbers = () => {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
refetch();
|
fetchPhoneNumbers(false);
|
||||||
setApplicationSid("");
|
setApplicationSid("");
|
||||||
setApplyMassEdit(false);
|
setApplyMassEdit(false);
|
||||||
|
setSelectAll(false);
|
||||||
|
setSelectedPhoneNumbers([]);
|
||||||
toastSuccess("Number routing updated successfully");
|
toastSuccess("Number routing updated successfully");
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@@ -111,7 +124,7 @@ export const PhoneNumbers = () => {
|
|||||||
if (phoneNumber) {
|
if (phoneNumber) {
|
||||||
deletePhoneNumber(phoneNumber.phone_number_sid)
|
deletePhoneNumber(phoneNumber.phone_number_sid)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
refetch();
|
fetchPhoneNumbers(false);
|
||||||
setPhoneNumber(null);
|
setPhoneNumber(null);
|
||||||
toastSuccess(
|
toastSuccess(
|
||||||
<>
|
<>
|
||||||
@@ -125,21 +138,43 @@ export const PhoneNumbers = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Initial account setup
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLocation();
|
|
||||||
if (user?.account_sid && user.scope === USER_ACCOUNT) {
|
if (user?.account_sid && user.scope === USER_ACCOUNT) {
|
||||||
setAccountSid(user?.account_sid);
|
setAccountSid(user?.account_sid);
|
||||||
|
} else {
|
||||||
|
setAccountSid(getAccountFilter() || accountSid);
|
||||||
}
|
}
|
||||||
|
setLocation();
|
||||||
}, [user]);
|
}, [user]);
|
||||||
|
|
||||||
|
// Combined effect for all data fetching
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ENABLE_PHONE_NUMBER_LAZY_LOAD) {
|
const prevValues = prevValuesRef.current;
|
||||||
setPhoneNumbers([]);
|
const currentSPId = currentServiceProvider?.service_provider_sid;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
refetch();
|
// Detect changes that require page reset
|
||||||
}, []);
|
const isFilterOrProviderChange =
|
||||||
|
prevValues.serviceProviderId !== currentSPId ||
|
||||||
|
prevValues.accountSid !== accountSid ||
|
||||||
|
prevValues.filter !== filter;
|
||||||
|
|
||||||
|
const isPageSizeChange =
|
||||||
|
prevValues.perPageFilter !== perPageFilter &&
|
||||||
|
prevValues.perPageFilter !== "25"; // Skip initial render
|
||||||
|
|
||||||
|
// Update ref for next comparison
|
||||||
|
prevValuesRef.current = {
|
||||||
|
serviceProviderId: currentSPId || "",
|
||||||
|
accountSid,
|
||||||
|
filter,
|
||||||
|
pageNumber,
|
||||||
|
perPageFilter,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch data with appropriate reset parameter
|
||||||
|
fetchPhoneNumbers(isFilterOrProviderChange || isPageSizeChange);
|
||||||
|
}, [currentServiceProvider, accountSid, filter, pageNumber, perPageFilter]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -160,6 +195,7 @@ export const PhoneNumbers = () => {
|
|||||||
<SearchFilter
|
<SearchFilter
|
||||||
placeholder="Filter phone numbers"
|
placeholder="Filter phone numbers"
|
||||||
filter={[filter, setFilter]}
|
filter={[filter, setFilter]}
|
||||||
|
delay={1000}
|
||||||
/>
|
/>
|
||||||
<ScopedAccess user={user} scope={Scope.service_provider}>
|
<ScopedAccess user={user} scope={Scope.service_provider}>
|
||||||
<AccountFilter
|
<AccountFilter
|
||||||
@@ -168,25 +204,12 @@ export const PhoneNumbers = () => {
|
|||||||
defaultOption
|
defaultOption
|
||||||
/>
|
/>
|
||||||
</ScopedAccess>
|
</ScopedAccess>
|
||||||
{ENABLE_PHONE_NUMBER_LAZY_LOAD && (
|
|
||||||
<ButtonGroup>
|
|
||||||
<Button
|
|
||||||
small
|
|
||||||
onClick={() => {
|
|
||||||
setPhoneNumbers(null);
|
|
||||||
refetch();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Search
|
|
||||||
</Button>
|
|
||||||
</ButtonGroup>
|
|
||||||
)}
|
|
||||||
</section>
|
</section>
|
||||||
<Section {...(hasLength(filteredPhoneNumbers) && { slim: true })}>
|
<Section {...(hasLength(phoneNumbers) && { slim: true })}>
|
||||||
<div className="list">
|
<div className="list">
|
||||||
{!hasValue(phoneNumbers) ? (
|
{!hasValue(phoneNumbers) ? (
|
||||||
<Spinner />
|
<Spinner />
|
||||||
) : hasLength(filteredPhoneNumbers) ? (
|
) : hasLength(phoneNumbers) ? (
|
||||||
<>
|
<>
|
||||||
<div className="item item--actions">
|
<div className="item item--actions">
|
||||||
{accountSid ? (
|
{accountSid ? (
|
||||||
@@ -200,7 +223,7 @@ export const PhoneNumbers = () => {
|
|||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
if (e.target.checked) {
|
if (e.target.checked) {
|
||||||
setSelectAll(true);
|
setSelectAll(true);
|
||||||
setSelectedPhoneNumbers(filteredPhoneNumbers);
|
setSelectedPhoneNumbers(phoneNumbers);
|
||||||
} else {
|
} else {
|
||||||
setSelectAll(false);
|
setSelectAll(false);
|
||||||
setSelectedPhoneNumbers([]);
|
setSelectedPhoneNumbers([]);
|
||||||
@@ -224,10 +247,8 @@ export const PhoneNumbers = () => {
|
|||||||
<Button
|
<Button
|
||||||
small
|
small
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleMassEdit();
|
|
||||||
setSelectAll(false);
|
|
||||||
setApplyMassEdit(true);
|
setApplyMassEdit(true);
|
||||||
setSelectedPhoneNumbers([]);
|
handleMassEdit();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Apply
|
Apply
|
||||||
@@ -249,7 +270,7 @@ export const PhoneNumbers = () => {
|
|||||||
</MS>
|
</MS>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{filteredPhoneNumbers.map((phoneNumber) => {
|
{phoneNumbers.map((phoneNumber) => {
|
||||||
return (
|
return (
|
||||||
<div className="item" key={phoneNumber.phone_number_sid}>
|
<div className="item" key={phoneNumber.phone_number_sid}>
|
||||||
<div className="item__info">
|
<div className="item__info">
|
||||||
@@ -385,6 +406,26 @@ export const PhoneNumbers = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Section>
|
</Section>
|
||||||
|
<footer>
|
||||||
|
<ButtonGroup>
|
||||||
|
<MS>
|
||||||
|
Total: {phoneNumbersTotal} record
|
||||||
|
{phoneNumbersTotal === 1 ? "" : "s"}
|
||||||
|
</MS>
|
||||||
|
{hasLength(phoneNumbers) && (
|
||||||
|
<Pagination
|
||||||
|
pageNumber={pageNumber}
|
||||||
|
setPageNumber={setPageNumber}
|
||||||
|
maxPageNumber={maxPageNumber}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<SelectFilter
|
||||||
|
id="page_filter"
|
||||||
|
filter={[perPageFilter, setPerPageFilter]}
|
||||||
|
options={PER_PAGE_SELECTION}
|
||||||
|
/>
|
||||||
|
</ButtonGroup>
|
||||||
|
</footer>
|
||||||
{phoneNumber && (
|
{phoneNumber && (
|
||||||
<DeletePhoneNumber
|
<DeletePhoneNumber
|
||||||
phoneNumber={phoneNumber}
|
phoneNumber={phoneNumber}
|
||||||
|
|||||||
@@ -87,10 +87,10 @@ export const RecentCalls = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useMemo(() => {
|
useMemo(() => {
|
||||||
|
setAccountSid(getAccountFilter() || accountSid);
|
||||||
|
if (!accountSid && user?.account_sid) setAccountSid(user?.account_sid);
|
||||||
if (getQueryFilter()) {
|
if (getQueryFilter()) {
|
||||||
const [date, direction, status] = getQueryFilter().split("/");
|
const [date, direction, status] = getQueryFilter().split("/");
|
||||||
setAccountSid(getAccountFilter() || accountSid);
|
|
||||||
if (!accountSid && user?.account_sid) setAccountSid(user?.account_sid);
|
|
||||||
setDateFilter(date);
|
setDateFilter(date);
|
||||||
setDirectionFilter(direction);
|
setDirectionFilter(direction);
|
||||||
setStatusFilter(status);
|
setStatusFilter(status);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import { ENABLE_HOSTED_SYSTEM, USER_ACCOUNT } from "src/api/constants";
|
|||||||
import type { UserData } from "src/store/types";
|
import type { UserData } from "src/store/types";
|
||||||
import { toastError } from "src/store";
|
import { toastError } from "src/store";
|
||||||
import {
|
import {
|
||||||
|
clearLocalStorage,
|
||||||
removeLocationBeforeOauth,
|
removeLocationBeforeOauth,
|
||||||
removeOauthState,
|
removeOauthState,
|
||||||
} from "src/store/localStore";
|
} from "src/store/localStore";
|
||||||
@@ -163,7 +164,7 @@ export const useProvideAuth = (): AuthStateContext => {
|
|||||||
postLogout()
|
postLogout()
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status === StatusCodes.NO_CONTENT) {
|
if (response.status === StatusCodes.NO_CONTENT) {
|
||||||
localStorage.clear();
|
clearLocalStorage();
|
||||||
sessionStorage.clear();
|
sessionStorage.clear();
|
||||||
sessionStorage.setItem(SESS_FLASH_MSG, MSG_LOGGED_OUT);
|
sessionStorage.setItem(SESS_FLASH_MSG, MSG_LOGGED_OUT);
|
||||||
window.location.href = ROUTE_LOGIN;
|
window.location.href = ROUTE_LOGIN;
|
||||||
|
|||||||
@@ -123,7 +123,18 @@ export const checkLocation = () => {
|
|||||||
|
|
||||||
if (currentLocation !== storedLocation) {
|
if (currentLocation !== storedLocation) {
|
||||||
localStorage.removeItem(storeQueryFilter);
|
localStorage.removeItem(storeQueryFilter);
|
||||||
localStorage.removeItem(storeAccountFilter);
|
// Keep storeAccountFilter in different location that user can search for same account
|
||||||
|
// in different location
|
||||||
|
// localStorage.removeItem(storeAccountFilter);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const clearLocalStorage = () => {
|
||||||
|
const toKeep = [storeActiveSP, storeAccountFilter];
|
||||||
|
Object.keys(localStorage).forEach((key) => {
|
||||||
|
if (!toKeep.includes(key)) {
|
||||||
|
localStorage.removeItem(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user