LFFE-25 Implementation of print layout and Printable Page

This commit is contained in:
AmirHossein Mahmoodi
2023-11-13 13:46:20 +03:30
parent 7a636aed07
commit 2a7707152e
12 changed files with 297 additions and 2 deletions

View File

@@ -167,3 +167,10 @@ This set of fonts are used in this project under the license: (.....)
url('./fonts/woff/Parastoo-Bold.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url('./fonts/ttf/Parastoo-Bold.ttf') format('truetype');
}
@font-face {
font-family: Bnazanin;
font-style: normal;
font-weight: normal;
src: url('./fonts/ttf/BNazanin.ttf') format('truetype');
}

Binary file not shown.

BIN
public/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -17,6 +17,9 @@
"online_message": "شما به اینترنت وصل هستید",
"offline_message": "اتصال شما به اینترنت قطع شده است",
"routing_to": "در حال انتقال به صفحه",
"data_not_found": "اطلاعاتی یافت نشد!",
"btn_print": "چاپ",
"button_back_to_previous": "بازگشت به صفحه قبل",
"header": {
"open_profile": "پروفایل",
"edit_profile": " پروفایل",
@@ -205,7 +208,9 @@
"upload_file": "صورت جلسه کارگروه استانی را بارگذاری کنید",
"upload_file_required": "وارد کردن صورت جلسه کارگروه استانی الزامیست",
"upload_file_unit": "فایل بارگذاری شده باید حداکثر 2Mb باشد",
"upload_file_format": "فرمت قابل قبول : png,jpg,pdf"
"upload_file_format": "فرمت قابل قبول : png,jpg,pdf",
"print_appraisal_confirmation": "چاپ تاییدیه ارزیابی",
"print_final_credit_amount": "چاپ صورت جلسه تعیین مبلغ نهایی"
},
"RefahiProvinceManager": {
"name": "نام",

9
public/print.scss Normal file
View File

@@ -0,0 +1,9 @@
@media print {
body {
margin: 0;
padding: 0;
}
@page {
size: A4;
}
}

View File

@@ -0,0 +1,18 @@
import {Avatar, Stack, Typography} from "@mui/material";
import useUser from "@/lib/app/hooks/useUser";
export default function ProfileData() {
const {user} = useUser();
return (
<Stack alignItems="center" spacing={2} sx={{p: 3}}>
<Avatar
sx={{width: "80px", height: "80px"}}
alt="User Image"
src={user.avatar}
/>
<Typography sx={{fontSize: 15, fontWeight: 600}} textAlign="center">
{user.username}
</Typography>
</Stack>
);
}

View File

@@ -0,0 +1,62 @@
import {Avatar, IconButton, Menu, Tooltip} from "@mui/material";
import {useState} from "react";
import ProfileData from "./ProfileData";
import ProfileOptions from "./ProfileOptions";
import {useTranslations} from "next-intl";
import useUser from "@/lib/app/hooks/useUser";
function ProfileMenu() {
const t = useTranslations();
const [anchorElUser, setAnchorElUser] = useState(null);
const {user} = useUser();
const handleOpenUserMenu = (event) => {
setAnchorElUser(event.currentTarget);
};
const handleCloseUserMenu = () => {
setAnchorElUser(null);
};
return (
<>
<Tooltip title={t("header.open_profile")} arrow>
<IconButton onClick={handleOpenUserMenu} sx={{p: 0}}>
<Avatar
sx={{
width: 24,
height: 24,
backgroundColor: "#fff",
color: "primary.main",
}}
alt="User Image"
src={user.avatar}
/>
</IconButton>
</Tooltip>
<Menu
MenuListProps={{sx: {py: 0}}}
sx={{
mt: 6,
}}
id="menu-appbar"
anchorEl={anchorElUser}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
keepMounted
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
open={Boolean(anchorElUser)}
onClose={handleCloseUserMenu}
>
<ProfileData/>
<ProfileOptions handleCloseUserMenu={handleCloseUserMenu}/>
</Menu>
</>
);
}
export default ProfileMenu;

View File

@@ -0,0 +1,49 @@
import {Box, Button, MenuItem, Typography} from "@mui/material";
import MeetingRoomIcon from "@mui/icons-material/MeetingRoom";
import useUser from "@/lib/app/hooks/useUser";
import {useTranslations} from "next-intl";
export default function ProfileOptionLogOut({handleCloseUserMenu}) {
const t = useTranslations();
const {clearToken} = useUser();
const handleClickLogOut = () => {
handleCloseUserMenu();
clearToken();
};
return (
<>
<MenuItem
component={Button}
to={{
pathname: "/dashboard/logout",
}}
sx={{
display: "flex",
justifyContent: "center",
borderTop: 1,
px: 3,
py: 1.5,
borderColor: "#e1e1e1",
textTransform: "unset",
}}
onClick={handleClickLogOut}
>
<Box sx={{display: "flex", alignItems: "center", flex: 1}}>
<Box
sx={{
display: "flex",
alignItems: "center",
color: "primary.main",
pr: 2,
}}
>
<MeetingRoomIcon/>
</Box>
<Typography sx={{flex: 1}} textAlign="start">
{t("header.logout")}
</Typography>
</Box>
</MenuItem>
</>
);
}

View File

@@ -0,0 +1,49 @@
import {Box, MenuItem, Typography} from "@mui/material";
import {NextLinkComposed} from "@/core/components/LinkRouting";
import {useTranslations} from "next-intl";
import headerProfileItems from "@/core/data/headerProfileItems";
import ProfileOptionLogOut from "./ProfileOptionLogOut";
export default function ProfileOptions({handleCloseUserMenu}) {
const t = useTranslations();
return (
<>
{headerProfileItems.map((profile_item) => (
<MenuItem
component={NextLinkComposed}
to={{
pathname: profile_item.route,
}}
sx={{
display: "flex",
justifyContent: "center",
borderTop: 1,
px: 3,
py: 1.5,
borderColor: "#e1e1e1",
}}
key={profile_item.key}
onClick={handleCloseUserMenu}
>
<Box sx={{display: "flex", alignItems: "center", flex: 1}}>
<Box
sx={{
display: "flex",
alignItems: "center",
color: "primary.main",
pr: 2,
}}
>
{profile_item.icon}
</Box>
<Typography sx={{flex: 1}} textAlign="start">
{t(profile_item.name)}
</Typography>
</Box>
</MenuItem>
))}
<ProfileOptionLogOut handleCloseUserMenu={handleCloseUserMenu}/>
</>
);
}

View File

@@ -0,0 +1,82 @@
import {Box, Container, Divider, Grid, Paper, Stack, Typography} from '@mui/material';
const PrintablePage = ({children, header, footer}) => (
<>
<Box sx={{width: "100%", height: 8, displayPrint: 'none'}}/>
<Container
sx={{
width: '21cm',
minHeight: '29.7cm',
margin: '0 auto',
backgroundColor: 'white',
p: '16px !important',
pb: footer ? '84px!important' : '',
position: 'relative'
}}
component="article" maxWidth="false">
<Grid container columns={5} sx={{pt: 2, px: 4, display: header ? '' : 'none'}}>
<Grid item xs={1}>
<Box sx={{width: 70}}>
<Box component={'img'} sx={{width: '100%', height: '100%', objectFit: 'contain'}}
src={'/images/logo.png'}/>
</Box>
</Grid>
<Grid item xs={3} sx={{textAlign: 'center'}}>
<Typography sx={{fontFamily: 'Bnazanin'}}>باسمه تعالی</Typography>
<Typography sx={{fontFamily: 'Bnazanin'}}>جمهوری اسلامی ایران</Typography>
<Typography sx={{fontFamily: 'Bnazanin', fontWeight: 'bold'}}>وزارت راه و
شهرسازی</Typography>
<Typography sx={{fontFamily: 'Bnazanin', fontWeight: 'bold'}}>سازمان
راهداری و حمل و نقل جاده
ای</Typography>
</Grid>
<Grid item xs={1}>
<Stack>
<Typography sx={{fontFamily: 'Bnazanin'}}>شماره:</Typography>
<Typography sx={{fontFamily: 'Bnazanin'}}>تاریخ:</Typography>
<Typography sx={{fontFamily: 'Bnazanin'}}>پیوست:</Typography>
</Stack>
</Grid>
</Grid>
<Paper elevation={0} sx={{px: 8}}>
{children}
</Paper>
<Box sx={{
position: 'absolute',
bottom: 0,
left: 0,
width: '100%',
px: 4,
pb: 2,
display: footer ? '' : 'none'
}}>
<Divider sx={{borderStyle: 'double', borderBottomWidth: 3, borderColor: '#000'}}/>
<Stack sx={{my: .5}}>
<Box sx={{textAlign: 'center'}}>
<Typography variant={'caption'} fontWeight={'bold'} component={'span'}
sx={{fontFamily: 'Bnazanin', px: 1}}> آدرس: تهران-بلوار
کشاورز-خیابان فلسطین جنوبی-خیابان
دمشق-پلاک17 </Typography>
<Typography variant={'caption'} fontWeight={'bold'} component={'span'}
sx={{fontFamily: 'Bnazanin', px: 1}}> تلفن: 88-88804379 </Typography>
<Typography variant={'caption'} fontWeight={'bold'} component={'span'}
sx={{fontFamily: 'Bnazanin', px: 1}}> تلفن گویا: 88804400 </Typography>
<Typography variant={'caption'} fontWeight={'bold'} component={'span'}
sx={{fontFamily: 'Bnazanin', px: 1}}> کدپستی: 1416753941 </Typography>
</Box>
<Box sx={{textAlign: 'center'}}>
<Typography variant={'caption'} fontWeight={'bold'} component={'span'}
sx={{fontFamily: 'Bnazanin', px: 2}}>صندوق پستی: 3773-14155</Typography>
<Typography variant={'caption'} fontWeight={'bold'} component={'span'}
sx={{fontFamily: 'Bnazanin', px: 2}}>پست الکترونیک: info@rmto.ir</Typography>
<Typography variant={'caption'} fontWeight={'bold'} component={'span'}
sx={{fontFamily: 'Bnazanin', px: 2}}>سایت الکترونیک: www.rmto.ir</Typography>
</Box>
</Stack>
</Box>
</Container>
<Box sx={{width: "100%", height: 8, displayPrint: 'none'}}/>
</>
);
export default PrintablePage;

View File

@@ -0,0 +1,12 @@
import WithAuthMiddleware from "@/middlewares/WithAuth";
import Print from "@/components/layouts/Print";
const PrintLayout = (props) => {
return (
<WithAuthMiddleware>
<Print {...props}/>
</WithAuthMiddleware>
)
}
export default PrintLayout

View File

@@ -1,8 +1,10 @@
import DashboardLayout from "@/layouts/DashboardLayout";
import {Fragment} from "react";
import PrintLayout from "@/layouts/PrintLayout";
const layoutList = {
DashboardLayout
DashboardLayout,
PrintLayout
}
const Layout = ({layout = {}, children}) => {