diff --git a/package.json b/package.json index a920731..b6a4742 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "react-icons": "^4.3.1", "react-router-dom": "6", "react-scripts": "5.0.1", + "react-to-print": "^2.14.7", "recoil": "^0.7.2", "styled-components": "^5.3.3", "typescript": "^4.6.3", diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..abb4118 --- /dev/null +++ b/src/App.css @@ -0,0 +1,10 @@ +@media print { + @page { + size: landscape; + } + + body { + transform: scale(0.80); + display: block; + } +} diff --git a/src/App.tsx b/src/App.tsx index 62fe008..e1c2d07 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -15,6 +15,7 @@ import { saveItem } from "./utils/localStorageUtil"; import { LANGUAGE_KEY } from "./constants"; import i18n from "./i18n"; import { getLanguageShortCode } from "./utils/languageUtil"; +import "./App.css"; const lightTheme = createTheme({ palette: { diff --git a/src/components/root/Appbar.tsx b/src/components/root/Appbar.tsx index 170a9a1..ecf9277 100644 --- a/src/components/root/Appbar.tsx +++ b/src/components/root/Appbar.tsx @@ -14,6 +14,7 @@ import { appbarTitle, isTimetableView, menuOpen, + printTimetable, subpage, timetableInfoDialogOpen, } from "../../states"; @@ -25,12 +26,14 @@ import { useNavigate } from "react-router-dom"; import InfoIconOutlined from "@mui/icons-material/InfoOutlined"; import SettingsIconOutlined from "@mui/icons-material/SettingsOutlined"; import SettingsMenuItems from "./SettingsMenuItems"; +import PrintIconOutlined from "@mui/icons-material/PrintOutlined"; const Appbar = (): ReactElement => { const [title] = useRecoilState(appbarTitle); const [timetableView, setTimetableView] = useRecoilState(isTimetableView); const setSelectedBranch = useSetRecoilState(actualTimetable); const [drawerOpen, setDrawerOpen] = useRecoilState(menuOpen); + const setPrintTimetable = useSetRecoilState(printTimetable); const setTimetableInfoOpen = useSetRecoilState(timetableInfoDialogOpen); const [settingsAnchorElement, setSettingsAnchorElement] = useState(); @@ -38,6 +41,7 @@ const Appbar = (): ReactElement => { const isSubpage = useRecoilValue(subpage); const navigate = useNavigate(); + const handlePrintTimetable = () => setPrintTimetable(true); const handleSettingsOpen = (event: React.MouseEvent) => setSettingsAnchorElement(event.currentTarget); const handleSettingsClose = () => setSettingsAnchorElement(null); @@ -106,15 +110,26 @@ const Appbar = (): ReactElement => { {timetableView ? ( - - - + <> + + + + + + + ) : null} diff --git a/src/states.ts b/src/states.ts index 5fa4f95..066c064 100644 --- a/src/states.ts +++ b/src/states.ts @@ -69,3 +69,8 @@ export const language = atom({ key: "language", default: getItem(LANGUAGE_KEY) ?? getLanguageShortCode(), }); + +export const printTimetable = atom({ + key: "printTimetable", + default: false, +}); diff --git a/src/views/Timetable.tsx b/src/views/Timetable.tsx index e9d3af0..a728698 100644 --- a/src/views/Timetable.tsx +++ b/src/views/Timetable.tsx @@ -1,4 +1,4 @@ -import React, { ReactElement, useEffect, useState } from "react"; +import React, { ReactElement, useEffect, useRef, useState } from "react"; import TimetableGrid from "../components/timetable/TimetableGrid"; import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil"; import { @@ -8,6 +8,7 @@ import { errorMessage, isTimetableView, networkError, + printTimetable, subpage, timetableTitle, } from "../states"; @@ -20,6 +21,7 @@ import { getSchoolDetails } from "../api/api"; import TimetableInfo from "../components/timetable/TimetableInfo"; import NetworkFailMessage from "../components/root/NetworkFailMessage"; import { changeTitle } from "../utils/titleUtil"; +import { useReactToPrint } from "react-to-print"; const Timetable = (): ReactElement => { const selectedBranch = useRecoilValue(actualTimetable); @@ -32,6 +34,12 @@ const Timetable = (): ReactElement => { const setErrorMessage = useSetRecoilState(errorMessage); const [netError, setNetworkErrorMessage] = useRecoilState(networkError); const setSubpage = useSetRecoilState(subpage); + const timetableRef = useRef(); + const handlePrint = useReactToPrint({ + content: () => timetableRef.current!, + removeAfterPrint: true, + }); + const [printClicked, setPrintTimetable] = useRecoilState(printTimetable); const { id } = useParams(); const onMount = () => { @@ -78,6 +86,13 @@ const Timetable = (): ReactElement => { document.title = changeTitle(`${schoolName} / ${selectedBranch!.name!}`); }, [selectedBranch, netError]); + useEffect(() => { + if (!printClicked) return; + + setPrintTimetable(false); + handlePrint(); + }, [printClicked]); + onMount(); const NetworkErrorContainer = () => ( @@ -97,7 +112,9 @@ const Timetable = (): ReactElement => { ); return ( + // @ts-ignore