diff --git a/src/api/api.ts b/src/api/api.ts new file mode 100644 index 00000000..42f2d77c --- /dev/null +++ b/src/api/api.ts @@ -0,0 +1,55 @@ +import {ILogo} from '@/components/PageLayout/Footer/Logo' +import {IPost} from '@/components/Posts/Post' +import {FlatPage} from '@/types/api/base' +import {MenuItemShort} from '@/types/api/cms' +import {Competition, Event} from '@/types/api/competition' +import {Profile} from '@/types/api/personal' +import {SeminarId} from '@/utils/useSeminarInfo' + +import {apiAxios} from './apiAxios' + +type OurCompetition = Omit & {history_events: Event[]} + +export const apiOptions = { + cms: { + flatPage: { + byUrl: (pageUrl: string) => ({ + queryKey: ['cms', 'flat-page', 'by-url', pageUrl], + queryFn: () => apiAxios.get(`/cms/flat-page/by-url/${pageUrl}`).then((res) => res.data), + }), + }, + logo: () => ({ + queryKey: ['cms', 'logo'], + queryFn: () => apiAxios.get('/cms/logo').then((res) => res.data), + }), + menuItem: { + onSite: (seminarId: SeminarId, type: 'menu' | 'footer') => ({ + queryKey: ['cms', 'menu-item', 'on-site', seminarId, type], + queryFn: () => + apiAxios.get(`/cms/menu-item/on-site/${seminarId}?type=${type}`).then((res) => res.data), + }), + }, + post: { + visible: (seminarId: SeminarId) => ({ + queryKey: ['cms', 'post', 'visible', seminarId], + queryFn: () => apiAxios.get(`/cms/post/visible?sites=${seminarId}`).then((res) => res.data), + }), + }, + }, + competition: { + competition: { + slug: (slug: string) => ({ + queryKey: ['competition', 'competition', 'slug', slug], + queryFn: () => apiAxios.get(`/competition/competition/slug/${slug}`).then((res) => res.data), + }), + }, + }, + personal: { + profiles: { + myprofile: () => ({ + queryKey: ['personal', 'profiles', 'myprofile'], + queryFn: () => apiAxios.get('/personal/profiles/myprofile').then((res) => res.data), + }), + }, + }, +} diff --git a/src/api/apiAxios.ts b/src/api/apiAxios.ts index c2f8589d..37f972fe 100644 --- a/src/api/apiAxios.ts +++ b/src/api/apiAxios.ts @@ -4,14 +4,16 @@ import {apiInterceptor} from '@/api/apiInterceptor' import {debugServer} from '@/utils/debugServer' import {getBackendServerUrl} from '@/utils/urlBase' -export const newApiAxios = (base: 'server' | 'client') => { +export const newApiAxios = () => { + const isServer = typeof window === 'undefined' + const instance = axios.create({ // axios requesty mozu byt z FE next serveru alebo z browsru. // - server vola BE URL (podla env vars) priamo // - browser vola lokalnu /api URL // - na deployed verzii (test.strom.sk, strom.sk) to chyti nginx a posle na deployed BE // - na localhoste to chyti next middleware, kde to rewritneme na BE URL (podla env vars) - baseURL: base === 'server' ? `${getBackendServerUrl()}/api` : '/api', + baseURL: isServer ? `${getBackendServerUrl()}/api` : '/api', // auth pozostava z comba: // 1. `sessionid` httpOnly cookie - nastavuje a maze su server pri login/logout // 2. CSRF hlavicka - server nastavuje cookie, ktorej hodnotu treba vlozit do hlavicky. axios riesi automaticky podla tohto configu @@ -22,7 +24,7 @@ export const newApiAxios = (base: 'server' | 'client') => { withCredentials: true, }) - if (base === 'server') { + if (isServer) { // prvy definovany interceptor bezi posledny. logujeme finalnu URL instance.interceptors.request.use((config) => { const {method, url, baseURL} = config @@ -44,6 +46,4 @@ export const newApiAxios = (base: 'server' | 'client') => { } // nasa "globalna" API instancia -export const apiAxios = newApiAxios('client') - -export const serverApiAxios = newApiAxios('server') +export const apiAxios = newApiAxios() diff --git a/src/api/commonQueries.ts b/src/api/commonQueries.ts new file mode 100644 index 00000000..94d16244 --- /dev/null +++ b/src/api/commonQueries.ts @@ -0,0 +1,15 @@ +import {QueryClient} from '@tanstack/react-query' + +import {getSeminarInfoFromPathname} from '@/utils/useSeminarInfo' + +import {apiOptions} from './api' + +export const commonQueries = (queryClient: QueryClient, resolvedUrl: string) => { + const {seminarId} = getSeminarInfoFromPathname(resolvedUrl) + + return [ + queryClient.prefetchQuery(apiOptions.cms.menuItem.onSite(seminarId, 'menu')), + queryClient.prefetchQuery(apiOptions.cms.menuItem.onSite(seminarId, 'footer')), + queryClient.prefetchQuery(apiOptions.cms.logo()), + ] +} diff --git a/src/components/PageLayout/Footer/Footer.tsx b/src/components/PageLayout/Footer/Footer.tsx index f2c75334..7ba22705 100644 --- a/src/components/PageLayout/Footer/Footer.tsx +++ b/src/components/PageLayout/Footer/Footer.tsx @@ -3,11 +3,10 @@ import Grid from '@mui/material/Unstable_Grid2' import {useQuery} from '@tanstack/react-query' import {FC} from 'react' -import {apiAxios} from '@/api/apiAxios' +import {apiOptions} from '@/api/api' import {Link} from '@/components/Clickable/Link' import {Loading} from '@/components/Loading/Loading' -import {ILogo, Logo} from '@/components/PageLayout/Footer/Logo' -import {MenuItemShort} from '@/types/api/cms' +import {Logo} from '@/components/PageLayout/Footer/Logo' import {useSeminarInfo} from '@/utils/useSeminarInfo' export const Footer: FC = () => { @@ -17,21 +16,11 @@ export const Footer: FC = () => { data: menuItemsData, isLoading: menuItemsIsLoading, error: menuItemsError, - } = useQuery({ - queryKey: ['cms', 'menu-item', 'on-site', seminarId, '?footer'], - queryFn: () => apiAxios.get(`/cms/menu-item/on-site/${seminarId}?type=footer`), - }) - const menuItems = menuItemsData?.data ?? [] + } = useQuery(apiOptions.cms.menuItem.onSite(seminarId, 'footer')) + const menuItems = menuItemsData ?? [] - const { - data: logosData, - isLoading: logosIsLoading, - error: logosError, - } = useQuery({ - queryKey: ['cms', 'logo'], - queryFn: () => apiAxios.get('/cms/logo'), - }) - const logos = logosData?.data.filter((logo) => !logo.disabled) ?? [] + const {data: logosData, isLoading: logosIsLoading, error: logosError} = useQuery(apiOptions.cms.logo()) + const logos = logosData?.filter((logo) => !logo.disabled) ?? [] return ( { } }, [router, fullWidthMenu]) - const {data: menuItemsData, isLoading: menuItemsIsLoading} = useQuery({ - queryKey: ['cms', 'menu-item', 'on-site', seminarId, '?menu'], - queryFn: () => apiAxios.get(`/cms/menu-item/on-site/${seminarId}?type=menu`), - }) - const menuItems = menuItemsData?.data ?? [] + const {data: menuItemsData, isLoading: menuItemsIsLoading} = useQuery( + apiOptions.cms.menuItem.onSite(seminarId, 'menu'), + ) + const menuItems = menuItemsData ?? [] const lg = useMediaQuery((theme) => theme.breakpoints.up('lg')) const iconSize = lg ? 34 : 24 diff --git a/src/components/Posts/Posts.tsx b/src/components/Posts/Posts.tsx index f73ffee5..966928b8 100644 --- a/src/components/Posts/Posts.tsx +++ b/src/components/Posts/Posts.tsx @@ -2,24 +2,21 @@ import {Stack, Typography} from '@mui/material' import {useQuery} from '@tanstack/react-query' import {FC} from 'react' -import {apiAxios} from '@/api/apiAxios' +import {apiOptions} from '@/api/api' import {useSeminarInfo} from '@/utils/useSeminarInfo' import {Loading} from '../Loading/Loading' -import {IPost, Post} from './Post' +import {Post} from './Post' export const Posts: FC = () => { + const {seminarId} = useSeminarInfo() + const { data: postsData, isLoading: postsIsLoading, error: postsError, - } = useQuery({ - queryKey: ['cms', 'post', 'visible'], - queryFn: () => apiAxios.get(`/cms/post/visible?sites=${seminarId}`), - }) - const posts = postsData?.data ?? [] - - const {seminarId} = useSeminarInfo() + } = useQuery(apiOptions.cms.post.visible(seminarId)) + const posts = postsData ?? [] if (postsIsLoading) return diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 6d2ff0d3..56bcbd63 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,6 +1,6 @@ import {CssBaseline} from '@mui/material' import {ThemeProvider} from '@mui/material/styles' -import {QueryClient, QueryClientProvider} from '@tanstack/react-query' +import {HydrationBoundary, QueryClient, QueryClientProvider} from '@tanstack/react-query' import {ReactQueryDevtools} from '@tanstack/react-query-devtools' import {isAxiosError} from 'axios' import {AppProps} from 'next/app' @@ -33,6 +33,10 @@ const ReactQueryProvider: FC = ({children}) => { if (failureCount >= 3) return false return true }, + // https://tanstack.com/query/latest/docs/framework/react/guides/ssr#initial-setup + // With SSR, we usually want to set some default staleTime + // above 0 to avoid refetching immediately on the client + staleTime: 60 * 1000, }, mutations: { // globalny error handler requestov cez useMutation @@ -89,18 +93,20 @@ const MyApp: FC = ({Component, pageProps}) => { - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/src/pages/malynar/[page].tsx b/src/pages/malynar/[page].tsx index 138effd6..d30d9c9e 100644 --- a/src/pages/malynar/[page].tsx +++ b/src/pages/malynar/[page].tsx @@ -1,5 +1,5 @@ -import StromStaticPage, {seminarBasedGetServerSideProps} from '../strom/[page]' +import StromStaticPage, {getServerSideProps} from '../strom/[page]' export default StromStaticPage -export const getServerSideProps = seminarBasedGetServerSideProps('malynar') +export {getServerSideProps} diff --git a/src/pages/malynar/admin/opravit-ulohu/[[...params]].tsx b/src/pages/malynar/admin/opravit-ulohu/[[...params]].tsx index 1113da34..9ac9579e 100644 --- a/src/pages/malynar/admin/opravit-ulohu/[[...params]].tsx +++ b/src/pages/malynar/admin/opravit-ulohu/[[...params]].tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../../strom/admin/opravit-ulohu/[[...params]]' +import Page, {getServerSideProps} from '../../../strom/admin/opravit-ulohu/[[...params]]' const ProblemAdministration: NextPage = () => { return } export default ProblemAdministration + +export {getServerSideProps} diff --git a/src/pages/malynar/admin/opravovanie/[[...params]].tsx b/src/pages/malynar/admin/opravovanie/[[...params]].tsx index a36a4021..9a26e0ef 100644 --- a/src/pages/malynar/admin/opravovanie/[[...params]].tsx +++ b/src/pages/malynar/admin/opravovanie/[[...params]].tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../../strom/admin/opravovanie/[[...params]]' +import Page, {getServerSideProps} from '../../../strom/admin/opravovanie/[[...params]]' const SemesterAdmnistration: NextPage = () => { return } export default SemesterAdmnistration + +export {getServerSideProps} diff --git a/src/pages/malynar/akcie/[[...params]].tsx b/src/pages/malynar/akcie/[[...params]].tsx index 95946921..9b9c82e5 100644 --- a/src/pages/malynar/akcie/[[...params]].tsx +++ b/src/pages/malynar/akcie/[[...params]].tsx @@ -1,5 +1,5 @@ -import StaticPage, {competitionBasedGetServerSideProps} from '../../strom/akcie/[[...params]]' +import StaticPage, {getServerSideProps} from '../../strom/akcie/[[...params]]' export default StaticPage -export const getServerSideProps = competitionBasedGetServerSideProps('malynar') +export {getServerSideProps} diff --git a/src/pages/malynar/archiv/[[...params]].tsx b/src/pages/malynar/archiv/[[...params]].tsx index 855016d3..4ba04763 100644 --- a/src/pages/malynar/archiv/[[...params]].tsx +++ b/src/pages/malynar/archiv/[[...params]].tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../strom/archiv/[[...params]]' +import Page, {getServerSideProps} from '../../strom/archiv/[[...params]]' const Archiv: NextPage = () => { return } export default Archiv + +export {getServerSideProps} diff --git a/src/pages/malynar/index.tsx b/src/pages/malynar/index.tsx index c381ff30..ed269c94 100644 --- a/src/pages/malynar/index.tsx +++ b/src/pages/malynar/index.tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../strom/index' +import Page, {getServerSideProps} from '../strom/index' -const Malynar: NextPage = () => { +const Home: NextPage = () => { return } -export default Malynar +export default Home + +export {getServerSideProps} diff --git a/src/pages/malynar/profil/index.tsx b/src/pages/malynar/profil/index.tsx index 9f0b40e0..de73e784 100644 --- a/src/pages/malynar/profil/index.tsx +++ b/src/pages/malynar/profil/index.tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../strom/profil/index' +import Page, {getServerSideProps} from '../../strom/profil/index' const Profile: NextPage = () => { return } export default Profile + +export {getServerSideProps} diff --git a/src/pages/malynar/profil/uprava.tsx b/src/pages/malynar/profil/uprava.tsx index 38473509..823e8c05 100644 --- a/src/pages/malynar/profil/uprava.tsx +++ b/src/pages/malynar/profil/uprava.tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../strom/profil/uprava' +import Page, {getServerSideProps} from '../../strom/profil/uprava' const Profil: NextPage = () => { return } export default Profil + +export {getServerSideProps} diff --git a/src/pages/malynar/registracia.tsx b/src/pages/malynar/registracia.tsx index ded2a74a..e088cb05 100644 --- a/src/pages/malynar/registracia.tsx +++ b/src/pages/malynar/registracia.tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../strom/registracia' +import Page, {getServerSideProps} from '../strom/registracia' const Register: NextPage = () => { return } export default Register + +export {getServerSideProps} diff --git a/src/pages/malynar/reset-password/[...resetToken].tsx b/src/pages/malynar/reset-password/[...resetToken].tsx index 4b4190a5..ca93e312 100644 --- a/src/pages/malynar/reset-password/[...resetToken].tsx +++ b/src/pages/malynar/reset-password/[...resetToken].tsx @@ -1,5 +1,5 @@ -import PasswordReset from '../../strom/reset-password/[...resetToken]' +import PasswordReset, {getServerSideProps} from '../../strom/reset-password/[...resetToken]' export default PasswordReset -export {getServerSideProps} from '../../strom/reset-password/[...resetToken]' +export {getServerSideProps} diff --git a/src/pages/malynar/verify-email/[verificationKey].tsx b/src/pages/malynar/verify-email/[verificationKey].tsx index 5b31acb6..e407d054 100644 --- a/src/pages/malynar/verify-email/[verificationKey].tsx +++ b/src/pages/malynar/verify-email/[verificationKey].tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../strom/verify-email/[verificationKey]' +import Page, {getServerSideProps} from '../../strom/verify-email/[verificationKey]' const Verify: NextPage = () => { return } export default Verify + +export {getServerSideProps} diff --git a/src/pages/malynar/vysledky/[[...params]].tsx b/src/pages/malynar/vysledky/[[...params]].tsx index 6b4b4a0b..b5b236c3 100644 --- a/src/pages/malynar/vysledky/[[...params]].tsx +++ b/src/pages/malynar/vysledky/[[...params]].tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../strom/vysledky/[[...params]]' +import Page, {getServerSideProps} from '../../strom/vysledky/[[...params]]' const Vysledky: NextPage = () => { return } export default Vysledky + +export {getServerSideProps} diff --git a/src/pages/malynar/zadania/[[...params]].tsx b/src/pages/malynar/zadania/[[...params]].tsx index b9babe59..5a94b932 100644 --- a/src/pages/malynar/zadania/[[...params]].tsx +++ b/src/pages/malynar/zadania/[[...params]].tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../strom/zadania/[[...params]]' +import Page, {getServerSideProps} from '../../strom/zadania/[[...params]]' const Zadania: NextPage = () => { return } export default Zadania + +export {getServerSideProps} diff --git a/src/pages/matik/[page].tsx b/src/pages/matik/[page].tsx index bde9ce90..d30d9c9e 100644 --- a/src/pages/matik/[page].tsx +++ b/src/pages/matik/[page].tsx @@ -1,5 +1,5 @@ -import StromStaticPage, {seminarBasedGetServerSideProps} from '../strom/[page]' +import StromStaticPage, {getServerSideProps} from '../strom/[page]' export default StromStaticPage -export const getServerSideProps = seminarBasedGetServerSideProps('matik') +export {getServerSideProps} diff --git a/src/pages/matik/admin/opravit-ulohu/[[...params]].tsx b/src/pages/matik/admin/opravit-ulohu/[[...params]].tsx index 1113da34..9ac9579e 100644 --- a/src/pages/matik/admin/opravit-ulohu/[[...params]].tsx +++ b/src/pages/matik/admin/opravit-ulohu/[[...params]].tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../../strom/admin/opravit-ulohu/[[...params]]' +import Page, {getServerSideProps} from '../../../strom/admin/opravit-ulohu/[[...params]]' const ProblemAdministration: NextPage = () => { return } export default ProblemAdministration + +export {getServerSideProps} diff --git a/src/pages/matik/admin/opravovanie/[[...params]].tsx b/src/pages/matik/admin/opravovanie/[[...params]].tsx index a36a4021..9a26e0ef 100644 --- a/src/pages/matik/admin/opravovanie/[[...params]].tsx +++ b/src/pages/matik/admin/opravovanie/[[...params]].tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../../strom/admin/opravovanie/[[...params]]' +import Page, {getServerSideProps} from '../../../strom/admin/opravovanie/[[...params]]' const SemesterAdmnistration: NextPage = () => { return } export default SemesterAdmnistration + +export {getServerSideProps} diff --git a/src/pages/matik/akcie/[[...params]].tsx b/src/pages/matik/akcie/[[...params]].tsx index 094abcf7..9b9c82e5 100644 --- a/src/pages/matik/akcie/[[...params]].tsx +++ b/src/pages/matik/akcie/[[...params]].tsx @@ -1,5 +1,5 @@ -import StaticPage, {competitionBasedGetServerSideProps} from '../../strom/akcie/[[...params]]' +import StaticPage, {getServerSideProps} from '../../strom/akcie/[[...params]]' export default StaticPage -export const getServerSideProps = competitionBasedGetServerSideProps('matik') +export {getServerSideProps} diff --git a/src/pages/matik/archiv/[[...params]].tsx b/src/pages/matik/archiv/[[...params]].tsx index 855016d3..4ba04763 100644 --- a/src/pages/matik/archiv/[[...params]].tsx +++ b/src/pages/matik/archiv/[[...params]].tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../strom/archiv/[[...params]]' +import Page, {getServerSideProps} from '../../strom/archiv/[[...params]]' const Archiv: NextPage = () => { return } export default Archiv + +export {getServerSideProps} diff --git a/src/pages/matik/index.tsx b/src/pages/matik/index.tsx index f34a7baf..ed269c94 100644 --- a/src/pages/matik/index.tsx +++ b/src/pages/matik/index.tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../strom/index' +import Page, {getServerSideProps} from '../strom/index' -const Matik: NextPage = () => { +const Home: NextPage = () => { return } -export default Matik +export default Home + +export {getServerSideProps} diff --git a/src/pages/matik/profil/index.tsx b/src/pages/matik/profil/index.tsx index 9f0b40e0..de73e784 100644 --- a/src/pages/matik/profil/index.tsx +++ b/src/pages/matik/profil/index.tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../strom/profil/index' +import Page, {getServerSideProps} from '../../strom/profil/index' const Profile: NextPage = () => { return } export default Profile + +export {getServerSideProps} diff --git a/src/pages/matik/profil/uprava.tsx b/src/pages/matik/profil/uprava.tsx index 38473509..823e8c05 100644 --- a/src/pages/matik/profil/uprava.tsx +++ b/src/pages/matik/profil/uprava.tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../strom/profil/uprava' +import Page, {getServerSideProps} from '../../strom/profil/uprava' const Profil: NextPage = () => { return } export default Profil + +export {getServerSideProps} diff --git a/src/pages/matik/registracia.tsx b/src/pages/matik/registracia.tsx index ded2a74a..e088cb05 100644 --- a/src/pages/matik/registracia.tsx +++ b/src/pages/matik/registracia.tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../strom/registracia' +import Page, {getServerSideProps} from '../strom/registracia' const Register: NextPage = () => { return } export default Register + +export {getServerSideProps} diff --git a/src/pages/matik/reset-password/[...resetToken].tsx b/src/pages/matik/reset-password/[...resetToken].tsx index 4b4190a5..ca93e312 100644 --- a/src/pages/matik/reset-password/[...resetToken].tsx +++ b/src/pages/matik/reset-password/[...resetToken].tsx @@ -1,5 +1,5 @@ -import PasswordReset from '../../strom/reset-password/[...resetToken]' +import PasswordReset, {getServerSideProps} from '../../strom/reset-password/[...resetToken]' export default PasswordReset -export {getServerSideProps} from '../../strom/reset-password/[...resetToken]' +export {getServerSideProps} diff --git a/src/pages/matik/verify-email/[verificationKey].tsx b/src/pages/matik/verify-email/[verificationKey].tsx index 5b31acb6..e407d054 100644 --- a/src/pages/matik/verify-email/[verificationKey].tsx +++ b/src/pages/matik/verify-email/[verificationKey].tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../strom/verify-email/[verificationKey]' +import Page, {getServerSideProps} from '../../strom/verify-email/[verificationKey]' const Verify: NextPage = () => { return } export default Verify + +export {getServerSideProps} diff --git a/src/pages/matik/vysledky/[[...params]].tsx b/src/pages/matik/vysledky/[[...params]].tsx index 6b4b4a0b..b5b236c3 100644 --- a/src/pages/matik/vysledky/[[...params]].tsx +++ b/src/pages/matik/vysledky/[[...params]].tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../strom/vysledky/[[...params]]' +import Page, {getServerSideProps} from '../../strom/vysledky/[[...params]]' const Vysledky: NextPage = () => { return } export default Vysledky + +export {getServerSideProps} diff --git a/src/pages/matik/zadania/[[...params]].tsx b/src/pages/matik/zadania/[[...params]].tsx index b9babe59..5a94b932 100644 --- a/src/pages/matik/zadania/[[...params]].tsx +++ b/src/pages/matik/zadania/[[...params]].tsx @@ -1,9 +1,11 @@ import {NextPage} from 'next' -import Page from '../../strom/zadania/[[...params]]' +import Page, {getServerSideProps} from '../../strom/zadania/[[...params]]' const Zadania: NextPage = () => { return } export default Zadania + +export {getServerSideProps} diff --git a/src/pages/strom/[page].tsx b/src/pages/strom/[page].tsx index 86956e99..2b178726 100644 --- a/src/pages/strom/[page].tsx +++ b/src/pages/strom/[page].tsx @@ -1,44 +1,47 @@ +import {dehydrate, QueryClient, useQuery} from '@tanstack/react-query' import {GetServerSideProps, NextPage} from 'next' +import {useRouter} from 'next/router' +import {ParsedUrlQuery} from 'querystring' -import {serverApiAxios} from '@/api/apiAxios' +import {apiOptions} from '@/api/api' +import {commonQueries} from '@/api/commonQueries' import {Markdown} from '@/components/Markdown/Markdown' import {PageLayout} from '@/components/PageLayout/PageLayout' -import {FlatPage} from '@/types/api/generated/base' -import {Seminar} from '@/utils/useSeminarInfo' -type StaticPageProps = { - title: string - content: string -} +// z nazvu suboru `[page]` - vzdy to musi byt string +const PARAM = 'page' +const getParam = (query: ParsedUrlQuery) => query[PARAM] as string + +const StaticPage: NextPage = () => { + const {query} = useRouter() + const requestedUrl = getParam(query) + + const {data} = useQuery(apiOptions.cms.flatPage.byUrl(requestedUrl)) -const StaticPage: NextPage = ({title, content}) => ( - - - -) + const content = data?.content ?? '' + const title = data?.title + return ( + + + + ) +} export default StaticPage -// wrapper aby sme to lahko vyuzili pre ostatne seminare a neduplikovali kod -export const seminarBasedGetServerSideProps = - (seminar: Seminar): GetServerSideProps => - async ({query}) => { - // `page` vychadza z nazvu suboru `[page]` - // tento check je hlavne pre typescript - parameter `page` by vzdy mal existovat a vzdy ako string - if (query?.page && typeof query.page === 'string') { - const requestedUrl = query.page - const {data} = await serverApiAxios.get(`/cms/flat-page/by-url/${requestedUrl}`) - // ked stranka neexistuje, vrati sa `content: ""`. teraz renderujeme stranku len ked je content neprazdny a server rovno vrati redirect. - // druha moznost by bola nechat prazdny content handlovat clienta - napriklad zobrazit custom error, ale nechat usera na neplatnej stranke. - // tretia moznost je miesto redirectu vratit nextovsku 404 - if (data?.content) { - return { - props: {content: data.content, title: data.title}, - } - } - } - - return {redirect: {destination: `/${seminar}`, permanent: false}} - } +export const getServerSideProps: GetServerSideProps = async ({query, resolvedUrl}) => { + const requestedUrl = getParam(query) -export const getServerSideProps = seminarBasedGetServerSideProps('strom') + const queryClient = new QueryClient() + + await Promise.all([ + ...commonQueries(queryClient, resolvedUrl), + queryClient.prefetchQuery(apiOptions.cms.flatPage.byUrl(requestedUrl)), + ]) + + return { + props: { + dehydratedState: dehydrate(queryClient), + }, + } +} diff --git a/src/pages/strom/admin/opravit-ulohu/[[...params]].tsx b/src/pages/strom/admin/opravit-ulohu/[[...params]].tsx index 1b3724f4..e7443abc 100644 --- a/src/pages/strom/admin/opravit-ulohu/[[...params]].tsx +++ b/src/pages/strom/admin/opravit-ulohu/[[...params]].tsx @@ -1,5 +1,7 @@ -import {NextPage} from 'next' +import {dehydrate, QueryClient} from '@tanstack/react-query' +import {GetServerSideProps, NextPage} from 'next' +import {commonQueries} from '@/api/commonQueries' import {PageLayout} from '@/components/PageLayout/PageLayout' import {ProblemAdministration as ProblemAdministrationComponent} from '@/components/ProblemAdministration/ProblemAdministration' @@ -10,3 +12,15 @@ const ProblemAdministration: NextPage = () => ( ) export default ProblemAdministration + +export const getServerSideProps: GetServerSideProps = async ({resolvedUrl}) => { + const queryClient = new QueryClient() + + await Promise.all([...commonQueries(queryClient, resolvedUrl)]) + + return { + props: { + dehydratedState: dehydrate(queryClient), + }, + } +} diff --git a/src/pages/strom/admin/opravovanie/[[...params]].tsx b/src/pages/strom/admin/opravovanie/[[...params]].tsx index cd9f01a0..95d4d767 100644 --- a/src/pages/strom/admin/opravovanie/[[...params]].tsx +++ b/src/pages/strom/admin/opravovanie/[[...params]].tsx @@ -1,5 +1,7 @@ -import {NextPage} from 'next' +import {dehydrate, QueryClient} from '@tanstack/react-query' +import {GetServerSideProps, NextPage} from 'next' +import {commonQueries} from '@/api/commonQueries' import {PageLayout} from '@/components/PageLayout/PageLayout' import {SemesterAdministration as SemesterAdministrationComponent} from '@/components/SemesterAdministration/SemesterAdministration' @@ -10,3 +12,15 @@ const SemesterAdmnistration: NextPage = () => ( ) export default SemesterAdmnistration + +export const getServerSideProps: GetServerSideProps = async ({resolvedUrl}) => { + const queryClient = new QueryClient() + + await Promise.all([...commonQueries(queryClient, resolvedUrl)]) + + return { + props: { + dehydratedState: dehydrate(queryClient), + }, + } +} diff --git a/src/pages/strom/akcie/[[...params]].tsx b/src/pages/strom/akcie/[[...params]].tsx index 70aad31d..6ca6b6c4 100644 --- a/src/pages/strom/akcie/[[...params]].tsx +++ b/src/pages/strom/akcie/[[...params]].tsx @@ -1,30 +1,40 @@ +import {dehydrate, QueryClient, useQuery} from '@tanstack/react-query' import {GetServerSideProps, NextPage} from 'next' +import {useRouter} from 'next/router' +import {ParsedUrlQuery} from 'querystring' -import {serverApiAxios} from '@/api/apiAxios' +import {apiOptions} from '@/api/api' +import {commonQueries} from '@/api/commonQueries' import {CompetitionPage} from '@/components/CompetitionPage/CompetitionPage' import {RulesPage} from '@/components/CompetitionPage/RulesPage' import {PageLayout} from '@/components/PageLayout/PageLayout' -import {Competition, Event} from '@/types/api/competition' -import {Seminar} from '@/utils/useSeminarInfo' -type OurCompetition = Omit & {history_events: Event[]} +// z nazvu suboru `[[...params]]` - vzdy to musi byt string[] +const PARAM = 'params' +const getParams = (query: ParsedUrlQuery) => { + const params = query[PARAM] as string[] + const requestedUrl = params[0] + const isRules = params.length === 2 && params[1] === 'pravidla' -type CompetitionPageProps = { - competition: OurCompetition - is_rules: boolean + return {requestedUrl, isRules} } -const StaticPage: NextPage = ({competition, is_rules}) => { +const StaticPage: NextPage = () => { + const {query} = useRouter() + const {requestedUrl, isRules} = getParams(query) + + const {data, isPending, isError} = useQuery(apiOptions.competition.competition.slug(requestedUrl)) + + // TODO: handle + if (isPending) return null + if (isError) return null + return ( - - {is_rules ? ( - + + {isRules ? ( + ) : ( - + )} ) @@ -32,37 +42,19 @@ const StaticPage: NextPage = ({competition, is_rules}) => export default StaticPage -// wrapper aby sme to lahko vyuzili pre ostatne seminare a neduplikovali kod -export const competitionBasedGetServerSideProps = - (seminar: Seminar): GetServerSideProps => - async ({query}) => { - const redirectToSeminar = {redirect: {destination: `/${seminar}`, permanent: false}} - - // `params` vychadza z nazvu suboru `[[...params]]` - // tento check je hlavne pre typescript - parameter `params` by vzdy mal existovat a mal by byt typu string[] - if (query?.params && Array.isArray(query.params) && query.params.length > 0) { - const requestedUrl = query.params[0] +export const getServerSideProps: GetServerSideProps = async ({query, resolvedUrl}) => { + const {requestedUrl} = getParams(query) - try { - const {data} = await serverApiAxios.get( - `/competition/competition/slug/${requestedUrl}`, - ) - if (!data) return redirectToSeminar + const queryClient = new QueryClient() - if (query.params.length === 2 && query.params[1] === 'pravidla') { - if (!data.rules) { - return {redirect: {destination: `/${seminar}/akcie/${requestedUrl}`, permanent: false}} - } - return {props: {competition: data, is_rules: true}} - } + await Promise.all([ + ...commonQueries(queryClient, resolvedUrl), + queryClient.prefetchQuery(apiOptions.competition.competition.slug(requestedUrl)), + ]) - return {props: {competition: data, is_rules: false}} - } catch { - return redirectToSeminar - } - } - - return redirectToSeminar + return { + props: { + dehydratedState: dehydrate(queryClient), + }, } - -export const getServerSideProps = competitionBasedGetServerSideProps('strom') +} diff --git a/src/pages/strom/archiv/[[...params]].tsx b/src/pages/strom/archiv/[[...params]].tsx index 43f26130..e197d726 100644 --- a/src/pages/strom/archiv/[[...params]].tsx +++ b/src/pages/strom/archiv/[[...params]].tsx @@ -1,5 +1,7 @@ -import {NextPage} from 'next' +import {dehydrate, QueryClient} from '@tanstack/react-query' +import {GetServerSideProps, NextPage} from 'next' +import {commonQueries} from '@/api/commonQueries' import {PageLayout} from '@/components/PageLayout/PageLayout' import {Archive} from '../../../components/Archive/Archive' @@ -13,3 +15,15 @@ const Archiv: NextPage = () => { } export default Archiv + +export const getServerSideProps: GetServerSideProps = async ({resolvedUrl}) => { + const queryClient = new QueryClient() + + await Promise.all([...commonQueries(queryClient, resolvedUrl)]) + + return { + props: { + dehydratedState: dehydrate(queryClient), + }, + } +} diff --git a/src/pages/strom/index.tsx b/src/pages/strom/index.tsx index 5d128163..9e2f15f3 100644 --- a/src/pages/strom/index.tsx +++ b/src/pages/strom/index.tsx @@ -1,12 +1,33 @@ -import {NextPage} from 'next' +import {dehydrate, QueryClient} from '@tanstack/react-query' +import {GetServerSideProps, NextPage} from 'next' +import {apiOptions} from '@/api/api' +import {commonQueries} from '@/api/commonQueries' import {PageLayout} from '@/components/PageLayout/PageLayout' import {Posts} from '@/components/Posts/Posts' +import {getSeminarInfoFromPathname} from '@/utils/useSeminarInfo' -const Strom: NextPage = () => ( +const Home: NextPage = () => ( ) -export default Strom +export default Home + +export const getServerSideProps: GetServerSideProps = async ({resolvedUrl}) => { + const {seminarId} = getSeminarInfoFromPathname(resolvedUrl) + + const queryClient = new QueryClient() + + await Promise.all([ + ...commonQueries(queryClient, resolvedUrl), + queryClient.prefetchQuery(apiOptions.cms.post.visible(seminarId)), + ]) + + return { + props: { + dehydratedState: dehydrate(queryClient), + }, + } +} diff --git a/src/pages/strom/profil/index.tsx b/src/pages/strom/profil/index.tsx index 467b6ace..f013b7d6 100644 --- a/src/pages/strom/profil/index.tsx +++ b/src/pages/strom/profil/index.tsx @@ -1,5 +1,7 @@ -import {NextPage} from 'next' +import {dehydrate, QueryClient} from '@tanstack/react-query' +import {GetServerSideProps, NextPage} from 'next' +import {commonQueries} from '@/api/commonQueries' import {PageLayout} from '@/components/PageLayout/PageLayout' import {ProfileDetail} from '@/components/Profile/ProfileDetail' @@ -10,3 +12,15 @@ const Profile: NextPage = () => ( ) export default Profile + +export const getServerSideProps: GetServerSideProps = async ({resolvedUrl}) => { + const queryClient = new QueryClient() + + await Promise.all([...commonQueries(queryClient, resolvedUrl)]) + + return { + props: { + dehydratedState: dehydrate(queryClient), + }, + } +} diff --git a/src/pages/strom/profil/uprava.tsx b/src/pages/strom/profil/uprava.tsx index a4b95216..12473ea2 100644 --- a/src/pages/strom/profil/uprava.tsx +++ b/src/pages/strom/profil/uprava.tsx @@ -1,5 +1,7 @@ -import {NextPage} from 'next' +import {dehydrate, QueryClient} from '@tanstack/react-query' +import {GetServerSideProps, NextPage} from 'next' +import {commonQueries} from '@/api/commonQueries' import {PageLayout} from '@/components/PageLayout/PageLayout' import {ProfileForm} from '@/components/Profile/ProfileForm' @@ -10,3 +12,15 @@ const Profil: NextPage = () => ( ) export default Profil + +export const getServerSideProps: GetServerSideProps = async ({resolvedUrl}) => { + const queryClient = new QueryClient() + + await Promise.all([...commonQueries(queryClient, resolvedUrl)]) + + return { + props: { + dehydratedState: dehydrate(queryClient), + }, + } +} diff --git a/src/pages/strom/registracia.tsx b/src/pages/strom/registracia.tsx index 3c4b0201..2fe83560 100644 --- a/src/pages/strom/registracia.tsx +++ b/src/pages/strom/registracia.tsx @@ -1,5 +1,7 @@ -import {NextPage} from 'next' +import {dehydrate, QueryClient} from '@tanstack/react-query' +import {GetServerSideProps, NextPage} from 'next' +import {commonQueries} from '@/api/commonQueries' import {PageLayout} from '@/components/PageLayout/PageLayout' import {RegisterForm} from '@/components/RegisterForm/RegisterForm' @@ -10,3 +12,15 @@ const Register: NextPage = () => ( ) export default Register + +export const getServerSideProps: GetServerSideProps = async ({resolvedUrl}) => { + const queryClient = new QueryClient() + + await Promise.all([...commonQueries(queryClient, resolvedUrl)]) + + return { + props: { + dehydratedState: dehydrate(queryClient), + }, + } +} diff --git a/src/pages/strom/reset-password/[...resetToken].tsx b/src/pages/strom/reset-password/[...resetToken].tsx index c1078dd8..8f96cda6 100644 --- a/src/pages/strom/reset-password/[...resetToken].tsx +++ b/src/pages/strom/reset-password/[...resetToken].tsx @@ -1,31 +1,49 @@ -import {NextPage} from 'next' +import {Typography} from '@mui/material' +import {dehydrate, QueryClient} from '@tanstack/react-query' +import {GetServerSideProps, NextPage} from 'next' +import {useRouter} from 'next/router' +import {ParsedUrlQuery} from 'querystring' +import {commonQueries} from '@/api/commonQueries' import {PageLayout} from '@/components/PageLayout/PageLayout' -import {PasswordResetForm, PasswordResetFormProps} from '@/components/PasswordReset/PasswordReset' +import {PasswordResetForm} from '@/components/PasswordReset/PasswordReset' -type QueryType = { - query?: { - resetToken: string | string[] - } +// z nazvu suboru `[...resetToken]` - vzdy to musi byt pole stringov, ale nevieme garantovat viac ako jeden segment +const PARAM = 'resetToken' +type Params = [string, ...(string | undefined)[]] +const getParams = (query: ParsedUrlQuery) => { + const params = query[PARAM] as Params + + const [token, uid] = params + + return {token, uid} } -const PasswordReset: NextPage = ({uid, token}) => ( - - - -) +const PasswordReset: NextPage = () => { + const {query} = useRouter() + const {uid, token} = getParams(query) + + return ( + + {uid ? ( + + ) : ( + Neplatný odkaz, chýbajúci parameter uid. + )} + + ) +} export default PasswordReset -export const getServerSideProps = async ({query}: QueryType) => { - const errorRedirect = {redirect: {destination: '/', permanent: false}} +export const getServerSideProps: GetServerSideProps = async ({resolvedUrl}) => { + const queryClient = new QueryClient() - if (query?.resetToken && Array.isArray(query.resetToken) && query.resetToken.length === 2) { - const token = query.resetToken[0] - const uid = query.resetToken[1] + await Promise.all([...commonQueries(queryClient, resolvedUrl)]) - if (typeof token === 'string' && typeof uid === 'string') return {props: {uid: uid, token: token}} + return { + props: { + dehydratedState: dehydrate(queryClient), + }, } - - return errorRedirect } diff --git a/src/pages/strom/verify-email/[verificationKey].tsx b/src/pages/strom/verify-email/[verificationKey].tsx index 6581fd8b..a9961e2c 100644 --- a/src/pages/strom/verify-email/[verificationKey].tsx +++ b/src/pages/strom/verify-email/[verificationKey].tsx @@ -1,5 +1,7 @@ -import {NextPage} from 'next' +import {dehydrate, QueryClient} from '@tanstack/react-query' +import {GetServerSideProps, NextPage} from 'next' +import {commonQueries} from '@/api/commonQueries' import {PageLayout} from '@/components/PageLayout/PageLayout' import {VerifyEmail} from '@/components/VerifyEmail/VerifyEmail' @@ -10,3 +12,15 @@ const Verify: NextPage = () => ( ) export default Verify + +export const getServerSideProps: GetServerSideProps = async ({resolvedUrl}) => { + const queryClient = new QueryClient() + + await Promise.all([...commonQueries(queryClient, resolvedUrl)]) + + return { + props: { + dehydratedState: dehydrate(queryClient), + }, + } +} diff --git a/src/pages/strom/vysledky/[[...params]].tsx b/src/pages/strom/vysledky/[[...params]].tsx index 75feae21..06dd64b2 100644 --- a/src/pages/strom/vysledky/[[...params]].tsx +++ b/src/pages/strom/vysledky/[[...params]].tsx @@ -1,5 +1,7 @@ -import {NextPage} from 'next' +import {dehydrate, QueryClient} from '@tanstack/react-query' +import {GetServerSideProps, NextPage} from 'next' +import {commonQueries} from '@/api/commonQueries' import {PageLayout} from '@/components/PageLayout/PageLayout' import {Results} from '@/components/Results/Results' @@ -12,3 +14,15 @@ const Vysledky: NextPage = () => { } export default Vysledky + +export const getServerSideProps: GetServerSideProps = async ({resolvedUrl}) => { + const queryClient = new QueryClient() + + await Promise.all([...commonQueries(queryClient, resolvedUrl)]) + + return { + props: { + dehydratedState: dehydrate(queryClient), + }, + } +} diff --git a/src/pages/strom/zadania/[[...params]].tsx b/src/pages/strom/zadania/[[...params]].tsx index cd3a049d..c50837a3 100644 --- a/src/pages/strom/zadania/[[...params]].tsx +++ b/src/pages/strom/zadania/[[...params]].tsx @@ -1,5 +1,7 @@ -import {NextPage} from 'next' +import {dehydrate, QueryClient} from '@tanstack/react-query' +import {GetServerSideProps, NextPage} from 'next' +import {commonQueries} from '@/api/commonQueries' import {PageLayout} from '@/components/PageLayout/PageLayout' import {Problems} from '@/components/Problems/Problems' @@ -12,3 +14,15 @@ const Zadania: NextPage = () => { } export default Zadania + +export const getServerSideProps: GetServerSideProps = async ({resolvedUrl}) => { + const queryClient = new QueryClient() + + await Promise.all([...commonQueries(queryClient, resolvedUrl)]) + + return { + props: { + dehydratedState: dehydrate(queryClient), + }, + } +} diff --git a/src/utils/AuthContainer.tsx b/src/utils/AuthContainer.tsx index d3203889..92c4df05 100644 --- a/src/utils/AuthContainer.tsx +++ b/src/utils/AuthContainer.tsx @@ -8,7 +8,7 @@ import {Login, Token} from '@/types/api/generated/user' import {MyPermissions} from '@/types/api/personal' // specialna axios instancia bez error handlingu pridaneho do `apiAxios` nizsie -const specialApiAxios = newApiAxios('client') +const specialApiAxios = newApiAxios() export const testAuthRequest = async () => specialApiAxios.get('/personal/profiles/mypermissions') diff --git a/src/utils/useProfile.ts b/src/utils/useProfile.ts index 1c819272..575ff026 100644 --- a/src/utils/useProfile.ts +++ b/src/utils/useProfile.ts @@ -1,7 +1,6 @@ import {useQuery} from '@tanstack/react-query' -import {apiAxios} from '@/api/apiAxios' -import {Profile} from '@/types/api/personal' +import {apiOptions} from '@/api/api' import {AuthContainer} from './AuthContainer' @@ -9,11 +8,9 @@ export const useProfile = () => { const {isAuthed} = AuthContainer.useContainer() const {data, isLoading} = useQuery({ - queryKey: ['personal', 'profiles', 'myprofile'], - queryFn: () => apiAxios.get(`/api/personal/profiles/myprofile`), + ...apiOptions.personal.profiles.myprofile(), enabled: isAuthed, }) - const profile = data?.data - return {profile, isLoading} + return {profile: data, isLoading} } diff --git a/src/utils/useSeminarInfo.ts b/src/utils/useSeminarInfo.ts index 2c9465c0..397e3344 100644 --- a/src/utils/useSeminarInfo.ts +++ b/src/utils/useSeminarInfo.ts @@ -1,7 +1,7 @@ import {useRouter} from 'next/router' export type Seminar = 'strom' | 'matik' | 'malynar' -type SeminarId = 0 | 1 | 2 +export type SeminarId = 0 | 1 | 2 const seminarToId: Record = { strom: 0, @@ -11,14 +11,20 @@ const seminarToId: Record = { export const seminarIds = Object.values(seminarToId) +export const getSeminarInfoFromPathname = (url: string) => { + const seminar = url.split('/')[1] as Seminar + const seminarId = seminarToId[seminar] + + return {seminar, seminarId} +} + export const useSeminarInfo = () => { const router = useRouter() // e.g. gets "matik" from "/matik/zadania/[[...params]]" - const seminar = router.pathname.slice(1).split('/', 1)[0] as Seminar - const seminarId = seminarToId[seminar] + const seminarInfo = getSeminarInfoFromPathname(router.pathname) - return {seminar, seminarId} + return seminarInfo } // for admin purposes we need backwards mapping from seminar ID to seminar name