From e09e174558f1dcfb33896c121ae1b80af00c16bf Mon Sep 17 00:00:00 2001 From: AmirHossein Mahmoodi Date: Tue, 14 Nov 2023 15:55:59 +0330 Subject: [PATCH] LFFE-25 print passenger boss and machinery expert --- public/locales/fa/app.json | 5 +- .../machinary-office/Buttons/printReport.jsx | 48 +++++++++++ .../Prints/report}/Content.jsx | 81 +++++-------------- .../machinary-office/Prints/report/index.jsx | 60 ++++++++++++++ .../machinary-office/TableToolbar.jsx | 12 +++ .../dashboard/machinary-office/index.jsx | 4 +- .../Buttons/printAppraisalConfirmation.jsx | 32 -------- .../Buttons/printFinalCreditAmount.jsx | 20 ++++- .../Prints/appraisal-confirmation/index.jsx | 34 -------- .../Prints/final-credit-amount/Content.jsx | 21 +---- .../Prints/final-credit-amount/index.jsx | 28 ++++++- .../dashboard/passenger-boss/TableToolbar.jsx | 2 - src/components/layouts/Print/Header/index.jsx | 31 ++++++- src/components/layouts/Print/index.jsx | 6 +- src/lib/app/contexts/print.jsx | 24 ++++++ src/lib/app/hooks/usePrint.jsx | 18 +++++ src/pages/_app.jsx | 9 ++- .../prints/report.jsx} | 8 +- 18 files changed, 275 insertions(+), 168 deletions(-) create mode 100644 src/components/dashboard/machinary-office/Buttons/printReport.jsx rename src/components/dashboard/{passenger-boss/Prints/appraisal-confirmation => machinary-office/Prints/report}/Content.jsx (52%) create mode 100644 src/components/dashboard/machinary-office/Prints/report/index.jsx create mode 100644 src/components/dashboard/machinary-office/TableToolbar.jsx delete mode 100644 src/components/dashboard/passenger-boss/Buttons/printAppraisalConfirmation.jsx delete mode 100644 src/components/dashboard/passenger-boss/Prints/appraisal-confirmation/index.jsx create mode 100644 src/lib/app/contexts/print.jsx create mode 100644 src/lib/app/hooks/usePrint.jsx rename src/pages/dashboard/{passenger-boss/prints/appraisal-confirmation.jsx => machinery-expert/prints/report.jsx} (59%) diff --git a/public/locales/fa/app.json b/public/locales/fa/app.json index d070036..f02bb6a 100644 --- a/public/locales/fa/app.json +++ b/public/locales/fa/app.json @@ -19,6 +19,7 @@ "routing_to": "در حال انتقال به صفحه", "data_not_found": "اطلاعاتی یافت نشد!", "btn_print": "چاپ", + "print_loading": "درحال پردازش اطلاعات ...", "button_back_to_previous": "بازگشت به صفحه قبل", "header": { "open_profile": "پروفایل", @@ -209,7 +210,6 @@ "upload_file_required": "وارد کردن صورت جلسه کارگروه استانی الزامیست", "upload_file_unit": "فایل بارگذاری شده باید حداکثر 2Mb باشد", "upload_file_format": "فرمت قابل قبول : png,jpg,pdf", - "print_appraisal_confirmation": "چاپ تاییدیه ارزیابی", "print_final_credit_amount": "چاپ صورت جلسه تعیین مبلغ نهایی" }, "RefahiProvinceManager": { @@ -308,7 +308,8 @@ "upload_file": "گزارش کارشناسی را بارگذاری کنید", "upload_file_required": "وارد کردن گزارش کارشناسی الزامیست", "upload_file_unit": "فایل بارگذاری شده باید حداکثر 2Mb باشد", - "upload_file_format": "فرمت قابل قبول : png,jpg,pdf" + "upload_file_format": "فرمت قابل قبول : png,jpg,pdf", + "print_report": "چاپ گزارش کارشناسی ماشین آلات" }, "UserManagement": { "name": "نام", diff --git a/src/components/dashboard/machinary-office/Buttons/printReport.jsx b/src/components/dashboard/machinary-office/Buttons/printReport.jsx new file mode 100644 index 0000000..47aab16 --- /dev/null +++ b/src/components/dashboard/machinary-office/Buttons/printReport.jsx @@ -0,0 +1,48 @@ +import PrintIcon from "@mui/icons-material/Print"; +import {Button, CircularProgress} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useRouter} from "next/router"; +import {useState} from "react"; +import useRequest from "@/lib/app/hooks/useRequest"; +import {GET_MACHINARY_OFFICE} from "@/core/data/apiRoutes"; +import usePrint from "@/lib/app/hooks/usePrint"; + +const PrintReport = () => { + const t = useTranslations(); + const router = useRouter() + const [loading, setLoading] = useState(false) + const requestServer = useRequest({auth: true, pending: false, success: {notification: {show: false}}}) + const {setPrintPage, setPrintTitle} = usePrint() + const clickHandler = () => { + setLoading(true) + const params = new URLSearchParams(); + params.set("start", '0'); + params.set("filters", '[]'); + params.set("sorting", '[]'); + requestServer(`${GET_MACHINARY_OFFICE}?${params}`, 'get').then((response) => { + const _data = response.data.data + setPrintPage(_data.length) + setPrintTitle(t('MachinaryOffice.print_report')) + sessionStorage.setItem('report-print', JSON.stringify(_data)) + router.push('/dashboard/machinery-expert/prints/report') + }).catch(() => { + setLoading(false) + }) + } + + return ( + + ) +} + +export default PrintReport \ No newline at end of file diff --git a/src/components/dashboard/passenger-boss/Prints/appraisal-confirmation/Content.jsx b/src/components/dashboard/machinary-office/Prints/report/Content.jsx similarity index 52% rename from src/components/dashboard/passenger-boss/Prints/appraisal-confirmation/Content.jsx rename to src/components/dashboard/machinary-office/Prints/report/Content.jsx index 3374d2a..8098ecb 100644 --- a/src/components/dashboard/passenger-boss/Prints/appraisal-confirmation/Content.jsx +++ b/src/components/dashboard/machinary-office/Prints/report/Content.jsx @@ -5,27 +5,16 @@ const Content = ({data}) => { return ( <> - - {'اداره کل راهداری و حمل و نقل جاده ای'} - {`استان ${data.province_name}`} - - {'موضوع: تاییدیه ارزیابی و تخصیص اعتبار'} - {'با سلام و احترام'} - + + {'گزارش کارشناسی ماشین آلات'} + + {'با توجه به نامه شماره'} { sx={{fontFamily: 'Bnazanin', fontWeight: 'bold'}}>تهران {'بازدید بعمل آمد که گزارش بازدید به شرخ ذیل مورد تایید می باشد.'} - + component={'span'}> {'در جلسه مطرح شد که نتیجه آن به شرح ذیل مورد تایید می باشد.'} + {'* با توجه به یک فقره پیش فاکتور پیوست ارائه شده از تعمیرگاه مجاز'} - - {'اصالت فاکتورهای شماره'} - 7563842 - {'و صحت اقلام لازم و قیمت آنها جهت نیازمندی بازسازی ناوگان مذکور به مبلغ'} - {'مبلغ پیشنهادی به عدد .............................................. ریال و به حروف ...................................................................... ریال می باشد.'} + {parseInt(2300000000).toLocaleString('en')} - {'ریال معادل'} - {parseInt(230000000).toLocaleString('en')} + }}> {'توضیحات : ................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................'} + {'تومان بابت هزینه کرد تعمیرات ناوگان فوق الذکر مورد تأیید می باشد.'} - - - - رئیس انجمن آقای ....... - انجمن صنفی رانندگان حمل و نقل مسافر - ...... - - - {'تعهدنامه'} - - {'اینجانب'} - امیرحسین محمودی + sx={{fontFamily: 'Bnazanin'}}> {'نام و نام خانوادگی کارشناس:'} {'مالک ناوگان اتوبوس | مینی بوس با مشخصات فوق الذکر بدینوسیله تعهد می نمایم مبلغ دریافتی وام را برابر پیش فاکتور ارائه شده صرف تعمیرات و بازسازی ناوگان نمایم و اگر خلاف این ثابت شود برابر مقررات با بنده برخورد شود و حق هیچگونه اعتراضی ندارم.'} - تاریخ و امضاء - + sx={{fontFamily: 'Bnazanin'}}> {'تاریخ و امضاء'} + diff --git a/src/components/dashboard/machinary-office/Prints/report/index.jsx b/src/components/dashboard/machinary-office/Prints/report/index.jsx new file mode 100644 index 0000000..54dca24 --- /dev/null +++ b/src/components/dashboard/machinary-office/Prints/report/index.jsx @@ -0,0 +1,60 @@ +import {useEffect, useState} from "react"; +import CenterLayout from "@/layouts/CenterLayout"; +import {useTranslations} from "next-intl"; +import {Stack, Typography} from "@mui/material"; +import Content from "@/components/dashboard/machinary-office/Prints/report/Content"; + +const ReportComponent = () => { + const t = useTranslations() + const [data, setData] = useState(null) + const [loading, setLoading] = useState(true) + const [isNotData, setIsNotData] = useState(true) + + useEffect(() => { + if (sessionStorage.getItem('report-print') === null) { + setLoading(false) + setIsNotData(true) + sessionStorage.setItem('report-print', 'seen') + } else if (sessionStorage.getItem('report-print') === 'seen') { + setLoading(false) + setData(null) + setIsNotData(true) + } else if (data) { + setLoading(false) + sessionStorage.setItem('report-print', 'seen') + setIsNotData(false) + } else { + setLoading(true) + setData(JSON.parse(sessionStorage.getItem('report-print'))) + setIsNotData(true) + } + }, [data]); + + return ( + + {loading ? ( + + + + {t('print_loading')} + + + + ) : !data ? ( + + + {t('data_not_found')} + + + ) : !data.length ? ( + + + {t('data_not_found')} + + + ) : data.map(item => )} + + ) +} + +export default ReportComponent \ No newline at end of file diff --git a/src/components/dashboard/machinary-office/TableToolbar.jsx b/src/components/dashboard/machinary-office/TableToolbar.jsx new file mode 100644 index 0000000..9704f95 --- /dev/null +++ b/src/components/dashboard/machinary-office/TableToolbar.jsx @@ -0,0 +1,12 @@ +import {Stack} from "@mui/material"; +import PrintReport from "@/components/dashboard/machinary-office/Buttons/printReport"; + +const TableToolbar = () => { + return ( + + + + ) +} + +export default TableToolbar \ No newline at end of file diff --git a/src/components/dashboard/machinary-office/index.jsx b/src/components/dashboard/machinary-office/index.jsx index 820519e..853c065 100644 --- a/src/components/dashboard/machinary-office/index.jsx +++ b/src/components/dashboard/machinary-office/index.jsx @@ -6,6 +6,7 @@ import TableRowActions from "./TableRowActions"; import moment from "jalali-moment"; import DataTable from "@/core/components/DataTable"; import MuiDatePicker from "@/core/components/MuiDatePicker"; +import TableToolbar from "@/components/dashboard/machinary-office/TableToolbar"; function DashboardMachinaryOfficeComponent() { const t = useTranslations(); @@ -160,7 +161,8 @@ function DashboardMachinaryOfficeComponent() { tableUrl={GET_MACHINARY_OFFICE} columns={columns} selectableRow={false} - enableCustomToolbar={false} + enableCustomToolbar={true} + CustomToolbar={TableToolbar} enableLastUpdate={true} sorting={[{ id: 'id', desc: false diff --git a/src/components/dashboard/passenger-boss/Buttons/printAppraisalConfirmation.jsx b/src/components/dashboard/passenger-boss/Buttons/printAppraisalConfirmation.jsx deleted file mode 100644 index 76da30b..0000000 --- a/src/components/dashboard/passenger-boss/Buttons/printAppraisalConfirmation.jsx +++ /dev/null @@ -1,32 +0,0 @@ -import PrintIcon from "@mui/icons-material/Print"; -import {Button, CircularProgress} from "@mui/material"; -import {useTranslations} from "next-intl"; -import {useState} from "react"; -import {useRouter} from "next/router"; - -const PrintAppraisalConfirmation = () => { - const t = useTranslations(); - const router = useRouter() - const [loading, setLoading] = useState(false) - const clickHandler = () => { - setLoading(true) - sessionStorage.setItem('appraisal-confirmation-print', JSON.stringify([])) - router.push('/dashboard/passenger-boss/prints/appraisal-confirmation') - } - - return ( - - ) -} - -export default PrintAppraisalConfirmation \ No newline at end of file diff --git a/src/components/dashboard/passenger-boss/Buttons/printFinalCreditAmount.jsx b/src/components/dashboard/passenger-boss/Buttons/printFinalCreditAmount.jsx index 3c43cf3..58a97af 100644 --- a/src/components/dashboard/passenger-boss/Buttons/printFinalCreditAmount.jsx +++ b/src/components/dashboard/passenger-boss/Buttons/printFinalCreditAmount.jsx @@ -3,15 +3,31 @@ import {Button, CircularProgress} from "@mui/material"; import {useTranslations} from "next-intl"; import {useRouter} from "next/router"; import {useState} from "react"; +import useRequest from "@/lib/app/hooks/useRequest"; +import {GET_PASSENGER_BOSS} from "@/core/data/apiRoutes"; +import usePrint from "@/lib/app/hooks/usePrint"; const PrintFinalCreditAmount = () => { const t = useTranslations(); const router = useRouter() const [loading, setLoading] = useState(false) + const requestServer = useRequest({auth: true, pending: false, success: {notification: {show: false}}}) + const {setPrintPage, setPrintTitle} = usePrint() const clickHandler = () => { setLoading(true) - sessionStorage.setItem('final-credit-amount-print', JSON.stringify([])) - router.push('/dashboard/passenger-boss/prints/final-credit-amount') + const params = new URLSearchParams(); + params.set("start", '0'); + params.set("filters", '[]'); + params.set("sorting", '[]'); + requestServer(`${GET_PASSENGER_BOSS}?${params}`, 'get').then((response) => { + const _data = response.data.data + setPrintPage(_data.length) + setPrintTitle(t('PassengerBoss.print_final_credit_amount')) + sessionStorage.setItem('final-credit-amount-print', JSON.stringify(_data)) + router.push('/dashboard/passenger-boss/prints/final-credit-amount') + }).catch(() => { + setLoading(false) + }) } return ( diff --git a/src/components/dashboard/passenger-boss/Prints/appraisal-confirmation/index.jsx b/src/components/dashboard/passenger-boss/Prints/appraisal-confirmation/index.jsx deleted file mode 100644 index 901e84a..0000000 --- a/src/components/dashboard/passenger-boss/Prints/appraisal-confirmation/index.jsx +++ /dev/null @@ -1,34 +0,0 @@ -import {useEffect, useState} from "react"; -import CenterLayout from "@/layouts/CenterLayout"; -import {useTranslations} from "next-intl"; -import {Typography} from "@mui/material"; -import Content from "@/components/dashboard/passenger-boss/Prints/appraisal-confirmation/Content"; - -const AppraisalConfirmationComponent = () => { - const t = useTranslations() - const [data, setData] = useState(null) - useEffect(() => { - if (sessionStorage.getItem('appraisal-confirmation-print') === null) { - sessionStorage.setItem('appraisal-confirmation-print', 'seen') - } else if (sessionStorage.getItem('appraisal-confirmation-print') === 'seen') { - setData(null) - } else if (data) { - sessionStorage.setItem('appraisal-confirmation-print', 'seen') - } else { - setData(JSON.parse(sessionStorage.getItem('appraisal-confirmation-print'))) - } - }, [data]); - return ( - <> - {!data ? ( - - - {t('data_not_found')} - - - ) : data.map(item => )} - - ) -} - -export default AppraisalConfirmationComponent \ No newline at end of file diff --git a/src/components/dashboard/passenger-boss/Prints/final-credit-amount/Content.jsx b/src/components/dashboard/passenger-boss/Prints/final-credit-amount/Content.jsx index 3c61db7..e9844ee 100644 --- a/src/components/dashboard/passenger-boss/Prints/final-credit-amount/Content.jsx +++ b/src/components/dashboard/passenger-boss/Prints/final-credit-amount/Content.jsx @@ -5,7 +5,7 @@ const Content = ({data}) => { return ( <> - + { fontSize: '1.2rem', textAlign: 'center' }}> {'فرم صورتجلسه تعیین مبلغ نهایی اعتبار'} - - + + {'با توجه به نامه شماره'} { {'در جلسه مطرح شد که نتیجه آن به شرح ذیل مورد تایید می باشد.'} - + {'با توجه به گزارش واصله از اداره ماشین آلات (نامه در پیوست موجود می باشد) جهت بازسازی ناوگان مذکور مبلغ .............................................. ریال معادل .............................................. تومان مورد تایید می باشد.'} @@ -115,19 +115,6 @@ const Content = ({data}) => { - - {'تعهدنامه'} - - {'اینجانب'} - امیرحسین محمودی - {'مالک ناوگان اتوبوس | مینی بوس با مشخصات فوق الذکر بدینوسیله تعهد می نمایم مبلغ دریافتی وام را برابر پیش فاکتور ارائه شده صرف تعمیرات و بازسازی ناوگان نمایم و اگر خلاف این ثابت شود برابر مقررات با بنده برخورد شود و حق هیچگونه اعتراضی ندارم.'} - تاریخ و امضاء - - ) diff --git a/src/components/dashboard/passenger-boss/Prints/final-credit-amount/index.jsx b/src/components/dashboard/passenger-boss/Prints/final-credit-amount/index.jsx index 927f8b9..9fd6a78 100644 --- a/src/components/dashboard/passenger-boss/Prints/final-credit-amount/index.jsx +++ b/src/components/dashboard/passenger-boss/Prints/final-credit-amount/index.jsx @@ -1,26 +1,46 @@ import {useEffect, useState} from "react"; import CenterLayout from "@/layouts/CenterLayout"; import {useTranslations} from "next-intl"; -import {Typography} from "@mui/material"; +import {Stack, Typography} from "@mui/material"; import Content from "@/components/dashboard/passenger-boss/Prints/final-credit-amount/Content"; const FinalCreditAmountComponent = () => { const t = useTranslations() const [data, setData] = useState(null) + const [loading, setLoading] = useState(true) + const [isNotData, setIsNotData] = useState(true) + useEffect(() => { if (sessionStorage.getItem('final-credit-amount-print') === null) { + setLoading(false) + setIsNotData(true) sessionStorage.setItem('final-credit-amount-print', 'seen') } else if (sessionStorage.getItem('final-credit-amount-print') === 'seen') { + setLoading(false) setData(null) + setIsNotData(true) } else if (data) { + setLoading(false) sessionStorage.setItem('final-credit-amount-print', 'seen') + setIsNotData(false) } else { + setLoading(true) setData(JSON.parse(sessionStorage.getItem('final-credit-amount-print'))) + setIsNotData(true) } }, [data]); + return ( - <> - {!data ? ( + + {loading ? ( + + + + {t('print_loading')} + + + + ) : !data ? ( {t('data_not_found')} @@ -33,7 +53,7 @@ const FinalCreditAmountComponent = () => { ) : data.map(item => )} - + ) } diff --git a/src/components/dashboard/passenger-boss/TableToolbar.jsx b/src/components/dashboard/passenger-boss/TableToolbar.jsx index 09f2f57..ed224f4 100644 --- a/src/components/dashboard/passenger-boss/TableToolbar.jsx +++ b/src/components/dashboard/passenger-boss/TableToolbar.jsx @@ -1,11 +1,9 @@ import {Stack} from "@mui/material"; -import PrintAppraisalConfirmation from "@/components/dashboard/passenger-boss/Buttons/printAppraisalConfirmation"; import PrintFinalCreditAmount from "@/components/dashboard/passenger-boss/Buttons/printFinalCreditAmount"; const TableToolbar = () => { return ( - ) diff --git a/src/components/layouts/Print/Header/index.jsx b/src/components/layouts/Print/Header/index.jsx index a2928bc..7c0d990 100644 --- a/src/components/layouts/Print/Header/index.jsx +++ b/src/components/layouts/Print/Header/index.jsx @@ -1,11 +1,15 @@ -import {AppBar, Button, Container, Stack, Toolbar, useTheme} from "@mui/material"; +import {AppBar, Button, Container, Stack, Toolbar, Typography, useTheme} from "@mui/material"; import {useTranslations} from "next-intl"; import {useRouter} from "next/router"; +import {useState} from "react"; +import usePrint from "@/lib/app/hooks/usePrint"; function Header({drawerWidth, handleDrawerToggle}) { const theme = useTheme(); const t = useTranslations() const router = useRouter() + const {printDetails} = usePrint() + const [disabled, setDisabled] = useState(false) return ( - + + {printDetails.title} + {'تعداد صفحه:'} {printDetails.count} + - diff --git a/src/components/layouts/Print/index.jsx b/src/components/layouts/Print/index.jsx index 6c66fd9..afa6585 100644 --- a/src/components/layouts/Print/index.jsx +++ b/src/components/layouts/Print/index.jsx @@ -1,14 +1,12 @@ import Header from "@/components/layouts/Print/Header"; -import {Paper, Toolbar} from "@mui/material"; +import {Toolbar} from "@mui/material"; const Print = (props) => { return ( <>
- - {props.children} - + {props.children} ) } diff --git a/src/lib/app/contexts/print.jsx b/src/lib/app/contexts/print.jsx new file mode 100644 index 0000000..20fd1dc --- /dev/null +++ b/src/lib/app/contexts/print.jsx @@ -0,0 +1,24 @@ +import {createContext, useReducer} from "react"; + +export const PrintContext = createContext(); + +const reducer = (state, action) => { + switch (action.type) { + case "SET_PRINT_PAGE": + return { + ...state, count: action.count + }; + case "SET_PRINT_TITLE": + return { + ...state, title: action.title + }; + } +}; +export const PrintProvider = ({children}) => { + const [printDetails, printDispatch] = useReducer(reducer, {title: '', count: 0}); + return ( + + {children} + + ); +}; \ No newline at end of file diff --git a/src/lib/app/hooks/usePrint.jsx b/src/lib/app/hooks/usePrint.jsx new file mode 100644 index 0000000..35a1017 --- /dev/null +++ b/src/lib/app/hooks/usePrint.jsx @@ -0,0 +1,18 @@ +import {useContext} from "react"; +import {PrintContext} from "@/lib/app/contexts/print"; + +const usePrint = () => { + const {printDetails, printDispatch} = useContext(PrintContext); + + const setPrintPage = (count) => { + printDispatch({type: 'SET_PRINT_PAGE', count}) + } + + const setPrintTitle = (title) => { + printDispatch({type: 'SET_PRINT_TITLE', title}) + } + + return {printDetails, setPrintPage, setPrintTitle} +}; + +export default usePrint; \ No newline at end of file diff --git a/src/pages/_app.jsx b/src/pages/_app.jsx index 8d2f3b0..9824687 100644 --- a/src/pages/_app.jsx +++ b/src/pages/_app.jsx @@ -9,6 +9,7 @@ import {NextIntlProvider} from "next-intl"; import TitlePage from "@/core/components/TitlePage"; import Layout from "@/layouts"; import {ToastProvider} from "@/lib/app/contexts/toast"; +import {PrintProvider} from "@/lib/app/contexts/print"; const App = ({Component, pageProps}) => { @@ -22,9 +23,11 @@ const App = ({Component, pageProps}) => { - - - + + + + + diff --git a/src/pages/dashboard/passenger-boss/prints/appraisal-confirmation.jsx b/src/pages/dashboard/machinery-expert/prints/report.jsx similarity index 59% rename from src/pages/dashboard/passenger-boss/prints/appraisal-confirmation.jsx rename to src/pages/dashboard/machinery-expert/prints/report.jsx index c2a021a..526851b 100644 --- a/src/pages/dashboard/passenger-boss/prints/appraisal-confirmation.jsx +++ b/src/pages/dashboard/machinery-expert/prints/report.jsx @@ -1,9 +1,9 @@ import {parse} from "next-useragent"; -import AppraisalConfirmationComponent from "@/components/dashboard/passenger-boss/Prints/appraisal-confirmation"; +import ReportComponent from "@/components/dashboard/machinary-office/Prints/report"; -export default function AppraisalConfirmation() { +export default function Report() { return ( - + ) } @@ -12,7 +12,7 @@ export async function getServerSideProps({req, locale}) { return { props: { messages: (await import(`&/locales/${locale}/app.json`)).default, - title: "Dashboard.passenger_boss_page", + title: "Dashboard.machinary_office_page", isBot, locale, layout: {name: 'PrintLayout'}