TF-102 Add network config
This commit is contained in:
@@ -15,6 +15,8 @@
|
|||||||
"Resend_code_in": "ارسال مجدد کد در",
|
"Resend_code_in": "ارسال مجدد کد در",
|
||||||
"seconds_later": "ثانیه دیگر",
|
"seconds_later": "ثانیه دیگر",
|
||||||
"upload_file_text": "بارگذاری فایل",
|
"upload_file_text": "بارگذاری فایل",
|
||||||
|
"online_message": "شما به اینترنت وصل هستید",
|
||||||
|
"offline_message": "اتصال شما به اینترنت قطع شده است",
|
||||||
"header": {
|
"header": {
|
||||||
"open_profile": "پروفایل",
|
"open_profile": "پروفایل",
|
||||||
"edit_profile": "ویرایش پروفایل",
|
"edit_profile": "ویرایش پروفایل",
|
||||||
|
|||||||
58
src/core/components/GlobalHead.jsx
Normal file
58
src/core/components/GlobalHead.jsx
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import Head from "next/head";
|
||||||
|
|
||||||
|
const GlobalHead = () => {
|
||||||
|
return (
|
||||||
|
<Head>
|
||||||
|
<meta
|
||||||
|
name="application-name"
|
||||||
|
content={process.env.NEXT_PUBLIC_API_NAME}
|
||||||
|
/>
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes"/>
|
||||||
|
<meta
|
||||||
|
name="apple-mobile-web-app-status-bar-style"
|
||||||
|
content="black-translucent"
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
name="apple-mobile-web-app-title"
|
||||||
|
content={process.env.NEXT_PUBLIC_API_NAME}
|
||||||
|
/>
|
||||||
|
<meta name="description" content="Marhaba does it for you"/>
|
||||||
|
<meta name="format-detection" content="telephone=no"/>
|
||||||
|
<meta name="format-detection" content="date=no"/>
|
||||||
|
<meta name="format-detection" content="address=no"/>
|
||||||
|
<meta name="format-detection" content="email=no"/>
|
||||||
|
<meta name="mobile-web-app-capable" content="yes"/>
|
||||||
|
<link rel="apple-touch-icon" href="/icons/maskable_icon_x512.png"/>
|
||||||
|
<link
|
||||||
|
rel="apple-touch-icon"
|
||||||
|
sizes="120x120"
|
||||||
|
href="/icons/maskable_icon_x128.png"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="apple-touch-icon"
|
||||||
|
sizes="180x180"
|
||||||
|
href="/icons/maskable_icon_x192.png"
|
||||||
|
/>
|
||||||
|
<meta name="google" content="notranslate"/>
|
||||||
|
<meta name="robots" content="noindex"/>
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no, user-scalable=no, viewport-fit=cover"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="icon"
|
||||||
|
type="image/svg"
|
||||||
|
sizes="32x32"
|
||||||
|
href="/icons/favicon.png"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="icon"
|
||||||
|
type="image/svg"
|
||||||
|
sizes="16x16"
|
||||||
|
href="/icons/favicon.png"
|
||||||
|
/>
|
||||||
|
</Head>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GlobalHead
|
||||||
34
src/core/components/NetworkComponent.jsx
Normal file
34
src/core/components/NetworkComponent.jsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import useNetwork from "@/lib/app/hooks/useNetwork";
|
||||||
|
import {useEffect, useRef} from "react";
|
||||||
|
import {toast} from "react-toastify";
|
||||||
|
import WifiIcon from '@mui/icons-material/Wifi';
|
||||||
|
import WifiOffIcon from '@mui/icons-material/WifiOff';
|
||||||
|
import {useTranslations} from "next-intl";
|
||||||
|
|
||||||
|
const NetworkComponent = () => {
|
||||||
|
const toastId = useRef(null);
|
||||||
|
const network = useNetwork()
|
||||||
|
const t = useTranslations()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (network.online) {
|
||||||
|
toast.update(toastId.current, {
|
||||||
|
type: toast.TYPE.SUCCESS,
|
||||||
|
render: t('online_message'),
|
||||||
|
autoClose: 2000,
|
||||||
|
closeButton: true,
|
||||||
|
closeOnClick: true,
|
||||||
|
icon: <WifiIcon/>
|
||||||
|
});
|
||||||
|
return
|
||||||
|
}
|
||||||
|
toast.dismiss()
|
||||||
|
toastId.current = toast.warn(t('offline_message'), {
|
||||||
|
autoClose: false, closeButton: false, closeOnClick: false, icon: <WifiOffIcon/>
|
||||||
|
})
|
||||||
|
}, [network.online]);
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NetworkComponent
|
||||||
@@ -2,12 +2,13 @@ import theme from "@/core/utils/theme";
|
|||||||
import useLanguage from "@/lib/app/hooks/useLanguage";
|
import useLanguage from "@/lib/app/hooks/useLanguage";
|
||||||
import useLoading from "@/lib/app/hooks/useLoading";
|
import useLoading from "@/lib/app/hooks/useLoading";
|
||||||
import useUser from "@/lib/app/hooks/useUser";
|
import useUser from "@/lib/app/hooks/useUser";
|
||||||
import Head from "next/head";
|
|
||||||
import NextNProgress from "nextjs-progressbar";
|
import NextNProgress from "nextjs-progressbar";
|
||||||
import {useEffect} from "react";
|
import {useEffect} from "react";
|
||||||
import {ToastContainer} from "react-toastify";
|
import {ToastContainer} from "react-toastify";
|
||||||
import useDirection from "@/lib/app/hooks/useDirection";
|
import useDirection from "@/lib/app/hooks/useDirection";
|
||||||
import "react-toastify/dist/ReactToastify.css";
|
import "react-toastify/dist/ReactToastify.css";
|
||||||
|
import NetworkComponent from "@/core/components/NetworkComponent";
|
||||||
|
import GlobalHead from "@/core/components/GlobalHead";
|
||||||
|
|
||||||
function AppLayout({children, isBot}) {
|
function AppLayout({children, isBot}) {
|
||||||
const {languageIsReady} = useLanguage();
|
const {languageIsReady} = useLanguage();
|
||||||
@@ -40,66 +41,16 @@ function AppLayout({children, isBot}) {
|
|||||||
if (!languageIsReady) return;
|
if (!languageIsReady) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (<>
|
||||||
<>
|
<GlobalHead/>
|
||||||
<Head>
|
<NextNProgress
|
||||||
<meta
|
color={theme.palette.secondary.dark}
|
||||||
name="application-name"
|
options={{showSpinner: false}}
|
||||||
content={process.env.NEXT_PUBLIC_API_NAME}
|
/>
|
||||||
/>
|
<ToastContainer position={directionApp === "ltr" ? "top-left" : "top-right"} rtl={directionApp === 'rtl'}/>
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes"/>
|
<NetworkComponent/>
|
||||||
<meta
|
{children}
|
||||||
name="apple-mobile-web-app-status-bar-style"
|
</>);
|
||||||
content="black-translucent"
|
|
||||||
/>
|
|
||||||
<meta
|
|
||||||
name="apple-mobile-web-app-title"
|
|
||||||
content={process.env.NEXT_PUBLIC_API_NAME}
|
|
||||||
/>
|
|
||||||
<meta name="description" content="Marhaba does it for you"/>
|
|
||||||
<meta name="format-detection" content="telephone=no"/>
|
|
||||||
<meta name="format-detection" content="date=no"/>
|
|
||||||
<meta name="format-detection" content="address=no"/>
|
|
||||||
<meta name="format-detection" content="email=no"/>
|
|
||||||
<meta name="mobile-web-app-capable" content="yes"/>
|
|
||||||
<link rel="apple-touch-icon" href="/icons/maskable_icon_x512.png"/>
|
|
||||||
<link
|
|
||||||
rel="apple-touch-icon"
|
|
||||||
sizes="120x120"
|
|
||||||
href="/icons/maskable_icon_x128.png"
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="apple-touch-icon"
|
|
||||||
sizes="180x180"
|
|
||||||
href="/icons/maskable_icon_x192.png"
|
|
||||||
/>
|
|
||||||
<meta name="google" content="notranslate"/>
|
|
||||||
<meta name="robots" content="noindex"/>
|
|
||||||
<meta
|
|
||||||
name="viewport"
|
|
||||||
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no, user-scalable=no, viewport-fit=cover"
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="icon"
|
|
||||||
type="image/svg"
|
|
||||||
sizes="32x32"
|
|
||||||
href="/images/logo.png"
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="icon"
|
|
||||||
type="image/svg"
|
|
||||||
sizes="16x16"
|
|
||||||
href="/images/logo.png"
|
|
||||||
/>
|
|
||||||
</Head>
|
|
||||||
<NextNProgress
|
|
||||||
color={theme.palette.secondary.dark}
|
|
||||||
options={{showSpinner: false}}
|
|
||||||
/>
|
|
||||||
<ToastContainer position={directionApp === "ltr" ? "top-left" : "top-right"} rtl={directionApp === 'rtl'}/>
|
|
||||||
{children}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AppLayout;
|
export default AppLayout;
|
||||||
58
src/lib/app/hooks/useNetwork.jsx
Normal file
58
src/lib/app/hooks/useNetwork.jsx
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import {useEffect, useState} from "react";
|
||||||
|
|
||||||
|
function getNetworkConnection() {
|
||||||
|
return (
|
||||||
|
navigator.connection ||
|
||||||
|
navigator.mozConnection ||
|
||||||
|
navigator.webkitConnection ||
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNetworkConnectionInfo() {
|
||||||
|
const connection = getNetworkConnection();
|
||||||
|
if (!connection) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
rtt: connection.rtt,
|
||||||
|
type: connection.type,
|
||||||
|
saveData: connection.saveData,
|
||||||
|
downLink: connection.downLink,
|
||||||
|
downLinkMax: connection.downLinkMax,
|
||||||
|
effectiveType: connection.effectiveType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function useNetwork() {
|
||||||
|
const [state, setState] = useState(() => {
|
||||||
|
return {
|
||||||
|
online: navigator.onLine,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
const handleOnline = () => {
|
||||||
|
setState((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
online: true,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
const handleOffline = () => {
|
||||||
|
setState((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
online: false,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("online", handleOnline);
|
||||||
|
window.addEventListener("offline", handleOffline);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("online", handleOnline);
|
||||||
|
window.removeEventListener("offline", handleOffline);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useNetwork;
|
||||||
@@ -4,27 +4,23 @@ import PendingNotification from "@/core/components/notifications/PendingNotifica
|
|||||||
import {useTranslations} from "next-intl";
|
import {useTranslations} from "next-intl";
|
||||||
import useUser from "@/lib/app/hooks/useUser";
|
import useUser from "@/lib/app/hooks/useUser";
|
||||||
import {errorRequest, errorResponse, errorSetting} from "@/core/utils/errorHandler";
|
import {errorRequest, errorResponse, errorSetting} from "@/core/utils/errorHandler";
|
||||||
|
import useNetwork from "@/lib/app/hooks/useNetwork";
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
auth: false,
|
auth: false, data: {}, requestOptions: {
|
||||||
data: {},
|
|
||||||
requestOptions: {
|
|
||||||
headers: {}
|
headers: {}
|
||||||
},
|
}, notification: true, pending: true, success: {
|
||||||
notification: true,
|
|
||||||
pending: true,
|
|
||||||
success: {
|
|
||||||
notification: {
|
notification: {
|
||||||
show: true,
|
show: true,
|
||||||
},
|
},
|
||||||
},
|
}, failed: {
|
||||||
failed: {
|
|
||||||
notification: {
|
notification: {
|
||||||
show: true,
|
show: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
const useRequest = (initOptions) => {
|
const useRequest = (initOptions) => {
|
||||||
|
const network = useNetwork()
|
||||||
const t = useTranslations()
|
const t = useTranslations()
|
||||||
const {token, clearToken} = useUser()
|
const {token, clearToken} = useUser()
|
||||||
let _options = {...defaultOptions, ...initOptions}
|
let _options = {...defaultOptions, ...initOptions}
|
||||||
@@ -32,20 +28,20 @@ const useRequest = (initOptions) => {
|
|||||||
function requestServer(url = '', method = 'get', options) {
|
function requestServer(url = '', method = 'get', options) {
|
||||||
_options = {..._options, ...options}
|
_options = {..._options, ...options}
|
||||||
if (_options.auth) _options = {
|
if (_options.auth) _options = {
|
||||||
..._options,
|
..._options, requestOptions: {
|
||||||
requestOptions: {
|
|
||||||
..._options.requestOptions,
|
..._options.requestOptions,
|
||||||
headers: {..._options.requestOptions.headers, authorization: `Bearer ${token}`}
|
headers: {..._options.requestOptions.headers, authorization: `Bearer ${token}`}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!network.online) {
|
||||||
|
reject()
|
||||||
|
return
|
||||||
|
}
|
||||||
if (_options.notification && _options.failed.notification.show && _options.pending) PendingNotification(t)
|
if (_options.notification && _options.failed.notification.show && _options.pending) PendingNotification(t)
|
||||||
axios({
|
axios({
|
||||||
url: url,
|
url: url, method: method, data: _options.data, ..._options.requestOptions
|
||||||
method: method,
|
|
||||||
data: _options.data,
|
|
||||||
..._options.requestOptions
|
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
successRequest(response, t, _options)
|
successRequest(response, t, _options)
|
||||||
|
|||||||
Reference in New Issue
Block a user