resolve conflict

This commit is contained in:
2023-08-07 14:09:01 +03:30
22 changed files with 434 additions and 104 deletions

View File

@@ -2,6 +2,18 @@ NEXT_PUBLIC_API_NAME = "Loan Facilities Dashboard"
NEXT_PUBLIC_DEFAULT_LANGUAGE = "fa"
NEXT_PUBLIC_DEFAULT_DIRECTION = "rtl"
NEXT_PUBLIC_PRIMARY_MAIN = "#084070"
NEXT_PUBLIC_PRIMARY_CONTRAST_TEXT = "#fff"
NEXT_PUBLIC_PRIMARY_LIGHT = "#2c6291"
NEXT_PUBLIC_PRIMARY_DARK = "#11293e"
NEXT_PUBLIC_SECONDARY_MAIN = "#FF4E00"
NEXT_PUBLIC_SECONDARY_CONTRAST_TEXT = "#fff"
NEXT_PUBLIC_SECONDARY_LIGHT = "#ed743e"
NEXT_PUBLIC_SECONDARY_DARK = "#ad3a07"
NEXT_PUBLIC_API_URL = "http://Your IP:3000"
NEXT_PUBLIC_BASE_URL = "https://loan.witel.ir"

View File

@@ -6,7 +6,7 @@ const nextConfig = {
defaultLocale: 'fa',
locales: ['fa'],
localeDetection: false,
},
}
}
module.exports = nextConfig

BIN
public/icons/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

1
public/images/403.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

1
public/images/404.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

1
public/images/500.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -20,7 +20,10 @@
},
"Titles": {
"title_login_page": "صفحه ورود",
"title_login_expert_page": "ورود کارشناس"
"title_login_expert_page": "ورود کارشناس",
"title_custom_404": "صفحه یافت نشد",
"title_custom_403": "عدم دسترسی",
"title_custom_500": "خطای سرور"
},
"sidebar": {
"dashboard": "داشبورد",
@@ -58,6 +61,14 @@
"link_routing_main_page": "صفحه اصلی",
"error_message_required": "اجباری!"
},
"ErrorPage": {
"custom_404": "صفحه مورد نظر یافت نشد | 404",
"custom_500": "دسترسی به سامانه امکانپذیر نمی باشد دقایقی دیگر تلاش نمائید | 500",
"custom_403": "شما دسترسی به این بخش را ندارید | 403",
"link_routing_back_to": "بازگشت به",
"link_routing_previuos_page": "صفحه قبل",
"link_routing_main_page": "صفحه اصلی"
},
"Dashboard": {
"dashboard_page": "داشبورد",
"passenger_boss_page": "رئیس مسافر",

57
public/manifest.json Normal file
View File

@@ -0,0 +1,57 @@
{
"short_name": "Loan Facilities Dashboard",
"name": "Loan Facilities Expert Dashboard",
"description": "Loan Facilities",
"version": "1.0.0",
"version_name": "1.0.0 beta",
"start_url": "/dashboard",
"orientation": "portrait",
"display": "standalone",
"theme_color": "#084070",
"background_color": "#084070",
"icons": [
{
"src": "/icons/maskable_icon.png",
"sizes": "any",
"type": "image/png"
},
{
"src": "/icons/maskable_icon_x48.png",
"sizes": "48x48",
"type": "image/png"
},
{
"src": "/icons/maskable_icon_x72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "/icons/maskable_icon_x96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "/icons/maskable_icon_x128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "/icons/maskable_icon_x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/maskable_icon_x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "/icons/maskable_icon_x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"categories": [
"government"
]
}

View File

@@ -90,7 +90,7 @@ const DashboardChangePasswordComponent = () => {
<Box
sx={{position: "relative", width: "100%", height: 200}}
>
<Image fill src="/images/change-password.svg" alt=""/>
<Image fill src="/images/change-password.svg" alt="" priority/>
</Box>
<Typography margin={2} variant="h4" textAlign="center">
{t("ChangePassword.typography_change_password")}

View File

@@ -0,0 +1,48 @@
import CenterLayout from "@/layouts/CenterLayout";
import FullPageLayout from "@/layouts/FullPageLayout";
import {Box, Button, Container, Stack, Typography} from "@mui/material";
import {NextLinkComposed} from "@/core/components/LinkRouting";
import {useTranslations} from "next-intl";
import Image from "next/image";
import TitlePage from "@/core/components/TitlePage";
const UnAuthorizedComponent = () => {
const t = useTranslations();
return (
<>
<TitlePage text="Titles.title_custom_403"/>
<FullPageLayout sx={{p: 1}}>
<CenterLayout>
<Container maxWidth="sm">
<Stack spacing={4} sx={{p: 4}}>
<Box sx={{position: "relative", width: "100%", height: 200}}>
<Image
fill
src="/images/403.svg"
alt={t("app_name")}
priority
/>
</Box>
<Typography margin={2} variant="h6" textAlign="center">
{t("ErrorPage.custom_403")}
</Typography>
<Button
variant="contained"
component={NextLinkComposed}
to={{
pathname: "/",
}}
>
{t("ErrorPage.link_routing_back_to")}{" "}
{t("ErrorPage.link_routing_main_page")}
</Button>
</Stack>
</Container>
</CenterLayout>
</FullPageLayout>
</>
);
};
export default UnAuthorizedComponent;

View File

@@ -0,0 +1,48 @@
import CenterLayout from "@/layouts/CenterLayout";
import FullPageLayout from "@/layouts/FullPageLayout";
import {Box, Button, Container, Stack, Typography} from "@mui/material";
import {NextLinkComposed} from "@/core/components/LinkRouting";
import {useTranslations} from "next-intl";
import Image from "next/image";
import TitlePage from "@/core/components/TitlePage";
const NotFoundComponent = () => {
const t = useTranslations();
return (
<>
<TitlePage text="Titles.title_custom_404"/>
<FullPageLayout sx={{p: 1}}>
<CenterLayout>
<Container maxWidth="sm">
<Stack spacing={4} sx={{p: 4}}>
<Box sx={{position: "relative", width: "100%", height: 200}}>
<Image
fill
src="/images/404.svg"
alt={t("app_name")}
priority
/>
</Box>
<Typography margin={2} variant="h6" textAlign="center">
{t("ErrorPage.custom_404")}
</Typography>
<Button
variant="contained"
component={NextLinkComposed}
to={{
pathname: "/",
}}
>
{t("ErrorPage.link_routing_back_to")}{" "}
{t("ErrorPage.link_routing_main_page")}
</Button>
</Stack>
</Container>
</CenterLayout>
</FullPageLayout>
</>
);
};
export default NotFoundComponent;

View File

@@ -0,0 +1,48 @@
import CenterLayout from "@/layouts/CenterLayout";
import FullPageLayout from "@/layouts/FullPageLayout";
import {Box, Button, Container, Stack, Typography} from "@mui/material";
import {NextLinkComposed} from "@/core/components/LinkRouting";
import {useTranslations} from "next-intl";
import Image from "next/image";
import TitlePage from "@/core/components/TitlePage";
const ServerErrorComponent = () => {
const t = useTranslations();
return (
<>
<TitlePage text="Titles.title_custom_500"/>
<FullPageLayout sx={{p: 1}}>
<CenterLayout>
<Container maxWidth="sm">
<Stack spacing={4} sx={{p: 4}}>
<Box sx={{position: "relative", width: "100%", height: 200}}>
<Image
fill
src="/images/500.svg"
alt={t("app_name")}
priority
/>
</Box>
<Typography margin={2} variant="h6" textAlign="center">
{t("ErrorPage.custom_500")}
</Typography>
<Button
variant="contained"
component={NextLinkComposed}
to={{
pathname: "/",
}}
>
{t("ErrorPage.link_routing_back_to")}{" "}
{t("ErrorPage.link_routing_main_page")}
</Button>
</Stack>
</Container>
</CenterLayout>
</FullPageLayout>
</>
);
};
export default ServerErrorComponent;

View File

@@ -27,100 +27,125 @@ const LoginComponent = () => {
//formik properties
const handleSubmit = async (values, props) => {
Notifications(directionApp, t);
await axios
.post(GET_USER_TOKEN, {
username: values.username, password: values.password,
username: values.username,
password: values.password,
})
.then(function (response) {
setToken(response.data.token);
})
.catch(function (error) {
Notifications(directionApp, t, error.response);
Notifications(directionApp, error.response, t);
props.setSubmitting(false);
});
};
const initialValues = {
username: "", password: "",
username: "",
password: "",
};
const validationSchema = Yup.object().shape({
username: Yup.string().required(t("LoginPage.error_message_required")),
password: Yup.string().required(t("LoginPage.error_message_required")),
});
return (<FullPageLayout sx={{p: 1}}>
<CenterLayout>
<Container maxWidth="sm">
<Paper elevation={0}>
<Formik
initialValues={initialValues}
onSubmit={handleSubmit}
validationSchema={validationSchema}
>
{(props) => (<Stack spacing={2} sx={{p: 2}}>
<Box
sx={{position: "relative", width: "100%", height: 200}}
>
<Image fill src="/images/login.svg" alt={t("app_name")}/>
</Box>
<Typography margin={2} variant="h4" textAlign="center">
{t("login_expert")}
</Typography>
<StyledForm sx={{width: "100%"}}>
<Stack spacing={3} sx={{p: 2}}>
<Field
as={TextField}
name="username"
variant="outlined"
label={t("LoginPage.text_field_user_name")}
placeholder={t("LoginPage.text_field_enter_your_username")}
type={"text"}
error={props.touched.username && props.errors.username ? true : false}
fullWidth
helperText={props.touched.username ? props.errors.username : null}
/>
<PasswordField
name="password"
label={t("LoginPage.text_field_password")}
error={props.touched.password && props.errors.password ? true : false}
helperText={props.touched.password ? props.errors.password : null}
placeholder={t("LoginPage.text_field_enter_your_password")}
/>
return (
<FullPageLayout sx={{p: 1}}>
<CenterLayout>
<Container maxWidth="sm">
<Paper elevation={0}>
<Formik
initialValues={initialValues}
onSubmit={handleSubmit}
validationSchema={validationSchema}
>
{(props) => (
<Stack spacing={2} sx={{p: 2}}>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
}}
sx={{position: "relative", width: "100%", height: 200}}
>
<Button
type="submit"
variant="contained"
fullWidth
size="medium"
endIcon={<LoginIcon/>}
disabled={props.isSubmitting ? true : false}
>
{t("LoginPage.button_submit")}
</Button>
<Image fill src="/images/login.svg" alt={t("app_name")}/>
</Box>
<Typography margin={2} variant="h4" textAlign="center">
{t("login_expert")}
</Typography>
<StyledForm sx={{width: "100%"}}>
<Stack spacing={3} sx={{p: 2}}>
<Field
as={TextField}
name="username"
variant="outlined"
label={t("LoginPage.text_field_user_name")}
placeholder={t(
"LoginPage.text_field_enter_your_username"
)}
type={"text"}
error={
props.touched.username && props.errors.username
? true
: false
}
fullWidth
helperText={
props.touched.username ? props.errors.username : null
}
/>
<PasswordField
name="password"
label={t("LoginPage.text_field_password")}
error={
props.touched.password && props.errors.password
? true
: false
}
helperText={
props.touched.password ? props.errors.password : null
}
placeholder={t(
"LoginPage.text_field_enter_your_password"
)}
/>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
}}
>
<Button
type="submit"
variant="contained"
fullWidth
size="medium"
endIcon={<LoginIcon/>}
disabled={props.isSubmitting ? true : false}
>
{t("LoginPage.button_submit")}
</Button>
</Box>
</Stack>
</StyledForm>
</Stack>
</StyledForm>
</Stack>)}
</Formik>
</Paper>
</Container>
</CenterLayout>
<Stack direction="row" alignItems="center" justifyContent="center">
<LinkRouting
sx={{margin: 2}}
href={backUrlDecodedPath ? decodeURIComponent(backUrlDecodedPath) : "/"}
>
{t("LoginPage.link_routing_back_to")}{" "}
{backUrlDecodedPath ? t("LoginPage.link_routing_previuos_page") : t("LoginPage.link_routing_main_page")}
</LinkRouting>
</Stack>
</FullPageLayout>);
)}
</Formik>
</Paper>
</Container>
</CenterLayout>
<Stack direction="row" alignItems="center" justifyContent="center">
<LinkRouting
sx={{margin: 2}}
href={
backUrlDecodedPath ? decodeURIComponent(backUrlDecodedPath) : "/"
}
>
{t("LoginPage.link_routing_back_to")}{" "}
{backUrlDecodedPath
? t("LoginPage.link_routing_previuos_page")
: t("LoginPage.link_routing_main_page")}
</LinkRouting>
</Stack>
</FullPageLayout>
);
};
export default LoginComponent;

View File

@@ -3,16 +3,16 @@ import {faIR} from "@mui/x-date-pickers/locales";
const theme = {
palette: {
primary: {
main: "#084070",
contrastText: "#fff",
light: "#2c6291",
dark: "#11293e",
main: process.env.NEXT_PUBLIC_PRIMARY_MAIN,
contrastText: process.env.NEXT_PUBLIC_PRIMARY_CONTRAST_TEXT,
light: process.env.NEXT_PUBLIC_PRIMARY_LIGHT,
dark: process.env.NEXT_PUBLIC_PRIMARY_DARK,
},
secondary: {
main: "#FF4E00",
contrastText: "#fff",
light: "#ed743e",
dark: "#ad3a07",
main: process.env.NEXT_PUBLIC_SECONDARY_MAIN,
contrastText: process.env.NEXT_PUBLIC_SECENDARY_CONTRAST_TEXT,
light: process.env.NEXT_PUBLIC_SECENDARY_LIGHT,
dark: process.env.NEXT_PUBLIC_SECENDARY_DARK,
},
},
faIR,

View File

@@ -83,13 +83,13 @@ function AppLayout({children, isBot}) {
rel="icon"
type="image/svg"
sizes="32x32"
href="/images/logo.png"
href="/icons/favicon.png"
/>
<link
rel="icon"
type="image/svg"
sizes="16x16"
href="/images/logo.png"
href="/icons/favicon.png"
/>
</Head>
<NextNProgress

View File

@@ -1,8 +1,10 @@
import {Divider, Stack, Toolbar, Typography} from "@mui/material";
import {useTranslations} from "next-intl";
import SidebarList from "./SidebarList";
import useUser from "@/lib/app/hooks/useUser";
const SidebarDrawer = ({handleDrawerToggle}) => {
const {user} = useUser()
const t = useTranslations();
return (
<>
@@ -12,10 +14,7 @@ const SidebarDrawer = ({handleDrawerToggle}) => {
{t("app_short_name")}
</Typography>
<Typography variant="caption">
{
t("expert") /* make if on thease t("user_welfare_services")
t("user_navy") */
}
{user.name} | {user.position}
</Typography>
</Stack>
</Toolbar>

View File

@@ -1,7 +1,7 @@
import {NextLinkComposed} from "@/core/components/LinkRouting";
import ExpandLess from "@mui/icons-material/ExpandLess";
import ExpandMore from "@mui/icons-material/ExpandMore";
import {Badge, ListItem, ListItemButton, ListItemIcon, ListItemText, Typography,} from "@mui/material";
import {Badge, IconButton, ListItem, ListItemButton, ListItemIcon, ListItemText, Typography,} from "@mui/material";
import {useTranslations} from "next-intl";
import {Fragment} from "react";
import SidebarListSubItem from "./SidebarListSubItem";
@@ -11,7 +11,19 @@ const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
return (
<Fragment key={item.key}>
<ListItem disablePadding sx={{display: "block"}}>
<ListItem disablePadding secondaryAction={
<IconButton>
<Badge
badgeContent="56"
color="error"
variant="standard"
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
/>
</IconButton>
}>
<ListItemButton
selected={item.selected}
{...(item.type == "page" && {
@@ -29,6 +41,7 @@ const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
sx={{
minHeight: 48,
}}
>
<ListItemIcon
sx={{
@@ -51,17 +64,9 @@ const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
}
/>
{item.type == "menu" &&
(item.showSubItem ? <ExpandLess/> : <ExpandMore/>)}
<Badge
badgeContent="21"
color="error"
variant="standard"
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
/>
</ListItemButton>
</ListItem>
{item.subItem && (

24
src/pages/403.jsx Normal file
View File

@@ -0,0 +1,24 @@
import {useEffect, useState} from "react";
import {useRouter} from "next/router";
import {NextIntlProvider} from "next-intl";
import UnAuthorizedComponent from "@/components/errors/403";
export default function Custom404() {
const router = useRouter()
const [messages, setMessages] = useState(null)
useEffect(() => {
const fetch = async () => {
const tempMessages = (await import(`&/locales/${router.locale}/app.json`)).default
setMessages(tempMessages)
}
fetch()
}, []);
if (!messages) return
return (
<NextIntlProvider messages={messages}>
<UnAuthorizedComponent/>
</NextIntlProvider>
);
}

25
src/pages/404.jsx Normal file
View File

@@ -0,0 +1,25 @@
import {useEffect, useState} from "react";
import {useRouter} from "next/router";
import {NextIntlProvider} from "next-intl";
import NotFoundComponent from "@/components/errors/404";
export default function Custom404() {
const router = useRouter()
const [messages, setMessages] = useState(null)
useEffect(() => {
const fetch = async () => {
const tempMessages = (await import(`&/locales/${router.locale}/app.json`)).default
setMessages(tempMessages)
}
fetch()
}, []);
if (!messages) return
return (
<NextIntlProvider messages={messages}>
<NotFoundComponent/>
</NextIntlProvider>
);
}

24
src/pages/500.jsx Normal file
View File

@@ -0,0 +1,24 @@
import {useEffect, useState} from "react";
import {useRouter} from "next/router";
import {NextIntlProvider} from "next-intl";
import ServerErrorComponent from "@/components/errors/500";
export default function Custom500() {
const router = useRouter()
const [messages, setMessages] = useState(null)
useEffect(() => {
const fetch = async () => {
const tempMessages = (await import(`&/locales/${router.locale}/app.json`)).default
setMessages(tempMessages)
}
fetch()
}, []);
if (!messages) return
return (
<NextIntlProvider messages={messages}>
<ServerErrorComponent/>
</NextIntlProvider>
);
}

View File

@@ -9,13 +9,14 @@ import {NextIntlProvider} from "next-intl";
import TitlePage from "@/core/components/TitlePage";
const App = ({Component, pageProps}) => {
return (
<>
<UserProvider>
<LanguageProvider>
<NextIntlProvider messages={pageProps.messages}>
<NextIntlProvider messages={pageProps.messages || {}}>
<MuiLayout isBot={pageProps.isBot}>
<TitlePage text={pageProps.title}/>
{pageProps.messages ? <TitlePage text={pageProps.title}/> : ''}
<LoadingProvider>
<AppLayout isBot={pageProps.isBot}>
<Component {...pageProps} />

View File

@@ -11,7 +11,7 @@ export default function MyDocument(props) {
<Head>
<meta name="theme-color" content={theme.palette.primary.main}/>
<meta name="emotion-insertion-point" content=""/>
<link rel="shortcut icon" href="/icons/favicon.ico"/>
<link rel="shortcut icon" href="/icons/favicon.png"/>
<link rel="manifest" href="/manifest.json"/>
{emotionStyleTags}
</Head>