From b2639463eafe1b366c3a4bcccd594118e603f4d1 Mon Sep 17 00:00:00 2001 From: rtrembecky Date: Sat, 11 Nov 2023 21:41:34 +0100 Subject: [PATCH 1/7] fix react admin forbidden errors --- src/components/Admin/dataProvider.ts | 95 +++++++--------------------- 1 file changed, 24 insertions(+), 71 deletions(-) diff --git a/src/components/Admin/dataProvider.ts b/src/components/Admin/dataProvider.ts index 6b0e7fdf..f6abbf9f 100644 --- a/src/components/Admin/dataProvider.ts +++ b/src/components/Admin/dataProvider.ts @@ -1,6 +1,6 @@ +import axios from 'axios' import {stringify} from 'querystring' -import {DataProvider, fetchUtils, RaRecord} from 'react-admin' -import {Cookies} from 'react-cookie' +import {DataProvider, RaRecord} from 'react-admin' // potencialne TODO: ak BE bude mat pagination, filter alebo sort, upravime a pouzijeme tento kod. // zatial je pagination aj sort rieseny client-side a len pre getList, filter/search nemame. @@ -19,21 +19,6 @@ import {Cookies} from 'react-cookie' // ordering: `${order === 'ASC' ? '' : '-'}${field}`, // }) -const cookies = new Cookies() - -const authFetchJson = (url: string, options?: Record) => { - const token = cookies.get('webstrom-token') - const authOptions = token - ? { - user: { - authenticated: true, - token: 'Token ' + token, - }, - } - : {} - return fetchUtils.fetchJson(url, Object.assign(authOptions, options)) -} - const dynamicSort = (key: string, order: string) => { const orderValue = order === 'ASC' ? 1 : -1 return (a: RaRecord, b: RaRecord) => { @@ -54,99 +39,67 @@ export const dataProvider: DataProvider = { // ...getPaginationQuery(params.pagination), // ...getOrderingQuery(params.sort), } - const {json} = await authFetchJson(`${apiUrl}/${resource}/?${stringify(query)}`) + const {data} = await axios.get(`${apiUrl}/${resource}/?${stringify(query)}`) // client-side sort const {field, order} = params.sort - json.sort(dynamicSort(field, order)) + + data.sort(dynamicSort(field, order)) // client-side pagination const {page, perPage} = params.pagination - const pagedData = json.slice((page - 1) * perPage, page * perPage) + const pagedData = data.slice((page - 1) * perPage, page * perPage) return { data: pagedData, - total: json.length, + total: data.length, } }, getOne: async (resource, params) => { - const {json} = await authFetchJson(`${apiUrl}/${resource}/${params.id}`) + const {data} = await axios.get(`${apiUrl}/${resource}/${params.id}`) - return { - data: json, - } + return {data} }, getMany: async (resource, params) => { - const data = await Promise.all(params.ids.map((id) => authFetchJson(`${apiUrl}/${resource}/${id}`))) + const data = await Promise.all(params.ids.map((id) => axios.get(`${apiUrl}/${resource}/${id}`))) - return { - data: data.map(({json}) => json), - } + return {data: data.map(({data}) => data)} }, // TODO: ak budeme pouzivat tuto funkciu, upravime podla getList (pagination, sort, filter). uprimne este neviem, pri com sa pouziva getManyReference: async (resource, params) => { const query = { [params.target]: params.id, } - const {json} = await authFetchJson(`${apiUrl}/${resource}/?${stringify(query)}`) + const {data} = await axios.get(`${apiUrl}/${resource}/?${stringify(query)}`) return { - data: json, - total: json.length, + data: data, + total: data.length, } }, update: async (resource, params) => { - const {json} = await authFetchJson(`${apiUrl}/${resource}/${params.id}`, { - method: 'PATCH', - body: JSON.stringify(params.data), - }) + const {data} = await axios.patch(`${apiUrl}/${resource}/${params.id}`, params.data) - return {data: json} + return {data} }, updateMany: async (resource, params) => { - const data = await Promise.all( - params.ids.map((id) => - authFetchJson(`${apiUrl}/${resource}/${id}`, { - method: 'PATCH', - body: JSON.stringify(params.data), - }), - ), - ) + const data = await Promise.all(params.ids.map((id) => axios.patch(`${apiUrl}/${resource}/${id}`, params.data))) - return { - data: data.map(({json}) => json), - } + return {data: data.map(({data}) => data)} }, create: async (resource, params) => { - const {json} = await authFetchJson(`${apiUrl}/${resource}`, { - method: 'POST', - body: JSON.stringify(params.data), - }) + const {data} = await axios.post(`${apiUrl}/${resource}`, params.data) - return { - data: json, - } + return {data} }, delete: async (resource, params) => { - const {json} = await authFetchJson(`${apiUrl}/${resource}/${params.id}`, { - method: 'DELETE', - }) + const {data} = await axios.delete(`${apiUrl}/${resource}/${params.id}`) - return { - data: json, - } + return {data} }, deleteMany: async (resource, params) => { - const data = await Promise.all( - params.ids.map((id) => - authFetchJson(`${apiUrl}/${resource}/${id}`, { - method: 'DELETE', - }), - ), - ) + const data = await Promise.all(params.ids.map((id) => axios.delete(`${apiUrl}/${resource}/${id}`))) - return { - data: data.map(({json}) => json.id), - } + return {data: data.map(({data}) => data.id)} }, } From c3944922ba1f6218b06dbf1d3a50bc6f2b586a6b Mon Sep 17 00:00:00 2001 From: rtrembecky Date: Sat, 11 Nov 2023 21:41:47 +0100 Subject: [PATCH 2/7] fix undefined record on first load --- src/components/Admin/custom/MyEditActions.tsx | 2 ++ src/components/Admin/custom/MyShowActions.tsx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/components/Admin/custom/MyEditActions.tsx b/src/components/Admin/custom/MyEditActions.tsx index d9db9c27..5652d64b 100644 --- a/src/components/Admin/custom/MyEditActions.tsx +++ b/src/components/Admin/custom/MyEditActions.tsx @@ -8,6 +8,8 @@ export const MyEditActions: FC = () => { const resource = useResourceContext() const record = useRecordContext() + // needed, undefined on first load + if (!record) return null const currentPathWithoutTab = `/${resource}/${record.id}` // '/cms/post/123' let to = `${currentPathWithoutTab}/show` // '/cms/post/123/show' diff --git a/src/components/Admin/custom/MyShowActions.tsx b/src/components/Admin/custom/MyShowActions.tsx index 60269cc7..e4abfd61 100644 --- a/src/components/Admin/custom/MyShowActions.tsx +++ b/src/components/Admin/custom/MyShowActions.tsx @@ -8,6 +8,8 @@ export const MyShowActions: FC = () => { const resource = useResourceContext() const record = useRecordContext() + // needed, undefined on first load + if (!record) return null const currentPathWithoutTab = `/${resource}/${record.id}/show` // '/cms/post/123/show' let to = `/${resource}/${record.id}` // '/cms/post/123' From 163debc5e63469758c593d6711621834c5a0916b Mon Sep 17 00:00:00 2001 From: rtrembecky Date: Sat, 11 Nov 2023 21:43:13 +0100 Subject: [PATCH 3/7] refactor menuItems style --- .../PageLayout/MenuMain/MenuMain.module.scss | 4 ---- .../PageLayout/MenuMain/MenuMain.module.scss.d.ts | 1 - src/components/PageLayout/MenuMain/MenuMain.tsx | 14 +++++++------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/components/PageLayout/MenuMain/MenuMain.module.scss b/src/components/PageLayout/MenuMain/MenuMain.module.scss index f337a2bc..af220445 100644 --- a/src/components/PageLayout/MenuMain/MenuMain.module.scss +++ b/src/components/PageLayout/MenuMain/MenuMain.module.scss @@ -50,10 +50,6 @@ padding: 2.5px; } -.menuItems { - margin-top: 176px; -} - .loading { position: absolute; top: 50%; diff --git a/src/components/PageLayout/MenuMain/MenuMain.module.scss.d.ts b/src/components/PageLayout/MenuMain/MenuMain.module.scss.d.ts index 874eeae3..e1d46efd 100644 --- a/src/components/PageLayout/MenuMain/MenuMain.module.scss.d.ts +++ b/src/components/PageLayout/MenuMain/MenuMain.module.scss.d.ts @@ -5,7 +5,6 @@ export type Styles = { menuButton: string menuCloseButton: string menuItem: string - menuItems: string menuOpenButton: string visible: string } diff --git a/src/components/PageLayout/MenuMain/MenuMain.tsx b/src/components/PageLayout/MenuMain/MenuMain.tsx index 513f727d..3be21381 100644 --- a/src/components/PageLayout/MenuMain/MenuMain.tsx +++ b/src/components/PageLayout/MenuMain/MenuMain.tsx @@ -1,4 +1,4 @@ -import {Theme, Typography, useMediaQuery} from '@mui/material' +import {Stack, Theme, Typography, useMediaQuery} from '@mui/material' import {useQuery} from '@tanstack/react-query' import axios from 'axios' import clsx from 'clsx' @@ -49,12 +49,12 @@ export const MenuMain: FC = () => { )} -
- {menuItems.map((menuItem: MenuItemInterface) => { - // `menuItem.url` je vo formate `/vysledky/` alebo `/akcie/matboj/` - return - })} -
+ + {menuItems.map(({id, caption, url}) => ( + // `url` je vo formate `/vysledky/` alebo `/akcie/matboj/` + + ))} + From 5a5355ac925f865babdf368933324367460d75c0 Mon Sep 17 00:00:00 2001 From: rtrembecky Date: Sat, 11 Nov 2023 21:43:35 +0100 Subject: [PATCH 4/7] add veduckovska menu section --- src/components/PageLayout/MenuMain/MenuMain.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/components/PageLayout/MenuMain/MenuMain.tsx b/src/components/PageLayout/MenuMain/MenuMain.tsx index 3be21381..e5c53e84 100644 --- a/src/components/PageLayout/MenuMain/MenuMain.tsx +++ b/src/components/PageLayout/MenuMain/MenuMain.tsx @@ -9,6 +9,7 @@ import {FC, useState} from 'react' import {CloseButton} from '@/components/CloseButton/CloseButton' import {Loading} from '@/components/Loading/Loading' import Menu from '@/svg/menu.svg' +import {useHasPermissions} from '@/utils/useHasPermissions' import {useSeminarInfo} from '@/utils/useSeminarInfo' import {Authentication} from '../Authentication/Authentication' @@ -23,6 +24,8 @@ interface MenuItemInterface { export const MenuMain: FC = () => { const {seminar, seminarId} = useSeminarInfo() + const {hasPermissions} = useHasPermissions() + const [isVisible, setIsVisible] = useState(true) const toggleMenu = () => setIsVisible((currentIsVisible) => !currentIsVisible) @@ -55,6 +58,12 @@ export const MenuMain: FC = () => { ))} + {hasPermissions && ( + + + + + )} From b547f376fa410e25d256d4121ef868d5827ddf71 Mon Sep 17 00:00:00 2001 From: rtrembecky Date: Sat, 11 Nov 2023 23:53:55 +0100 Subject: [PATCH 5/7] fix - the props are not injected after RA upgrade --- .../Admin/Competition/CompetitionList.tsx | 6 +++--- src/components/Admin/custom/MyArrayField.tsx | 5 +++-- src/components/Admin/custom/MyEditActions.tsx | 4 ++-- .../Admin/resources/cms/post/PostCreate.tsx | 15 +++------------ .../Admin/resources/cms/post/PostEdit.tsx | 16 +++------------- .../Admin/resources/cms/post/PostList.tsx | 6 +++--- .../Admin/resources/cms/post/PostShow.tsx | 5 ++--- 7 files changed, 19 insertions(+), 38 deletions(-) diff --git a/src/components/Admin/Competition/CompetitionList.tsx b/src/components/Admin/Competition/CompetitionList.tsx index a8b0c64c..9d2453ba 100644 --- a/src/components/Admin/Competition/CompetitionList.tsx +++ b/src/components/Admin/Competition/CompetitionList.tsx @@ -1,10 +1,10 @@ import {FC} from 'react' -import {ArrayField, Datagrid, DateField, List, ListProps, TextField} from 'react-admin' +import {ArrayField, Datagrid, DateField, List, TextField} from 'react-admin' // TODO: premysliet a prerobit rozhranie, mozno ako u postov - pri kliku na riadok ukazat Show, kde budu priklady // (nie ako teraz v zanorenom Datagride) -export const CompetitionList: FC = (props) => ( - +export const CompetitionList: FC = () => ( + diff --git a/src/components/Admin/custom/MyArrayField.tsx b/src/components/Admin/custom/MyArrayField.tsx index 5a1e86e1..85e64cd6 100644 --- a/src/components/Admin/custom/MyArrayField.tsx +++ b/src/components/Admin/custom/MyArrayField.tsx @@ -1,12 +1,13 @@ import {Chip} from '@mui/material' import {FC} from 'react' -import {FieldProps} from 'react-admin' +import {FieldProps, useRecordContext} from 'react-admin' type MyArrayFieldProps = FieldProps & { formatNumber?: (v: number) => string } -export const MyArrayField: FC = ({record, source, formatNumber}) => { +export const MyArrayField: FC = ({source, formatNumber}) => { + const record = useRecordContext() if (!record || !source) return null const array = record[source] as (string | number)[] | undefined diff --git a/src/components/Admin/custom/MyEditActions.tsx b/src/components/Admin/custom/MyEditActions.tsx index 5652d64b..cc372204 100644 --- a/src/components/Admin/custom/MyEditActions.tsx +++ b/src/components/Admin/custom/MyEditActions.tsx @@ -1,9 +1,9 @@ import {FC} from 'react' -import {EditActionsProps, ListButton, ShowButton, TopToolbar, useRecordContext, useResourceContext} from 'react-admin' +import {ListButton, ShowButton, TopToolbar, useRecordContext, useResourceContext} from 'react-admin' // eslint-disable-next-line node/no-extraneous-import import {useLocation} from 'react-router-dom' -export const MyEditActions: FC = () => { +export const MyEditActions: FC = () => { const {pathname} = useLocation() // bud '/cms/post/123' alebo '/cms/post/123/1' (prvy tab) const resource = useResourceContext() diff --git a/src/components/Admin/resources/cms/post/PostCreate.tsx b/src/components/Admin/resources/cms/post/PostCreate.tsx index 09967412..5b8a5a12 100644 --- a/src/components/Admin/resources/cms/post/PostCreate.tsx +++ b/src/components/Admin/resources/cms/post/PostCreate.tsx @@ -1,20 +1,11 @@ import {FC} from 'react' -import { - ArrayInput, - Create, - CreateProps, - FormTab, - required, - SimpleFormIterator, - TabbedForm, - TextInput, -} from 'react-admin' +import {ArrayInput, Create, FormTab, required, SimpleFormIterator, TabbedForm, TextInput} from 'react-admin' import {MyDateInput} from '@/components/Admin/custom/MyDateInput' import {SitesCheckboxInput} from '@/components/Admin/custom/SitesCheckboxInput' -export const PostCreate: FC = (props) => ( - +export const PostCreate: FC = () => ( + {/* */} diff --git a/src/components/Admin/resources/cms/post/PostEdit.tsx b/src/components/Admin/resources/cms/post/PostEdit.tsx index 20e664b9..ce21a24e 100644 --- a/src/components/Admin/resources/cms/post/PostEdit.tsx +++ b/src/components/Admin/resources/cms/post/PostEdit.tsx @@ -1,22 +1,12 @@ import {FC} from 'react' -import { - ArrayInput, - Edit, - EditProps, - FormTab, - NumberInput, - required, - SimpleFormIterator, - TabbedForm, - TextInput, -} from 'react-admin' +import {ArrayInput, Edit, FormTab, NumberInput, required, SimpleFormIterator, TabbedForm, TextInput} from 'react-admin' import {MyDateInput} from '@/components/Admin/custom/MyDateInput' import {MyEditActions} from '@/components/Admin/custom/MyEditActions' import {SitesCheckboxInput} from '@/components/Admin/custom/SitesCheckboxInput' -export const PostEdit: FC = (props) => ( - } redirect="show" mutationMode="undoable"> +export const PostEdit: FC = () => ( + } redirect="show" mutationMode="undoable"> diff --git a/src/components/Admin/resources/cms/post/PostList.tsx b/src/components/Admin/resources/cms/post/PostList.tsx index 2ac8607d..b34fed3a 100644 --- a/src/components/Admin/resources/cms/post/PostList.tsx +++ b/src/components/Admin/resources/cms/post/PostList.tsx @@ -1,8 +1,8 @@ import {FC} from 'react' -import {Datagrid, DateField, List, ListProps, NumberField, TextField} from 'react-admin' +import {Datagrid, DateField, List, NumberField, TextField} from 'react-admin' -export const PostList: FC = (props) => ( - +export const PostList: FC = () => ( + diff --git a/src/components/Admin/resources/cms/post/PostShow.tsx b/src/components/Admin/resources/cms/post/PostShow.tsx index 2d8b9667..63148d3d 100644 --- a/src/components/Admin/resources/cms/post/PostShow.tsx +++ b/src/components/Admin/resources/cms/post/PostShow.tsx @@ -5,7 +5,6 @@ import { DateField, NumberField, Show, - ShowProps, SimpleShowLayout, Tab, TabbedShowLayout, @@ -15,8 +14,8 @@ import { import {MyShowActions} from '@/components/Admin/custom/MyShowActions' import {SitesArrayField} from '@/components/Admin/custom/SitesArrayField' -export const PostShow: FC = (props) => ( - }> +export const PostShow: FC = () => ( + }> From 3d6f7bef6d2e9fe3e9dd6664a468e4fefc8ce794 Mon Sep 17 00:00:00 2001 From: rtrembecky Date: Sat, 11 Nov 2023 23:54:31 +0100 Subject: [PATCH 6/7] adjust MyDateInput as of date format currently coming from BE --- src/components/Admin/custom/MyDateInput.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/Admin/custom/MyDateInput.tsx b/src/components/Admin/custom/MyDateInput.tsx index 63d1fc98..01d5ab3d 100644 --- a/src/components/Admin/custom/MyDateInput.tsx +++ b/src/components/Admin/custom/MyDateInput.tsx @@ -2,8 +2,13 @@ import {DateTime} from 'luxon' import {ComponentProps, FC} from 'react' import {DateInput} from 'react-admin' +const backendFormat = 'dd.MM.yyyy HH:mm:ss' + +// used to convert BE weird format of 01.01.2020 18:00:00 to 01-01-2020 input format // https://moment.github.io/luxon/#/formatting -const dateFormatter = (v: string) => DateTime.fromISO(v).toISODate() +const dateFormatter = (v: string) => DateTime.fromFormat(v, backendFormat).toISODate() + +// used to convert input format of 01-01-2020 to 01-01-2020TT00:00:00.000+02:00 BE-expected format // https://moment.github.io/luxon/#/parsing const dateParser = (v: string) => DateTime.fromISO(v).toISO() From 987adf2b4acb63ece7438226dd83dc52525a6fe3 Mon Sep 17 00:00:00 2001 From: rtrembecky Date: Sun, 12 Nov 2023 00:46:15 +0100 Subject: [PATCH 7/7] todo po BE fixe --- src/components/Admin/custom/MyDateInput.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Admin/custom/MyDateInput.tsx b/src/components/Admin/custom/MyDateInput.tsx index 01d5ab3d..94a6389c 100644 --- a/src/components/Admin/custom/MyDateInput.tsx +++ b/src/components/Admin/custom/MyDateInput.tsx @@ -6,6 +6,7 @@ const backendFormat = 'dd.MM.yyyy HH:mm:ss' // used to convert BE weird format of 01.01.2020 18:00:00 to 01-01-2020 input format // https://moment.github.io/luxon/#/formatting +// TODO: ale blbost, upravi sa to aj tak nazad na ISO vs ISODate: https://github.com/ZdruzenieSTROM/webstrom-backend/issues/257 const dateFormatter = (v: string) => DateTime.fromFormat(v, backendFormat).toISODate() // used to convert input format of 01-01-2020 to 01-01-2020TT00:00:00.000+02:00 BE-expected format