diff --git a/rsconcept/frontend/src/backend/auth/useResetPassword.tsx b/rsconcept/frontend/src/backend/auth/useResetPassword.tsx index 040f7963..f7de68a9 100644 --- a/rsconcept/frontend/src/backend/auth/useResetPassword.tsx +++ b/rsconcept/frontend/src/backend/auth/useResetPassword.tsx @@ -23,7 +23,7 @@ export const useResetPassword = () => { data: IResetPasswordDTO, // onSuccess?: () => void ) => resetMutation.mutate(data, { onSuccess }), - isPending: resetMutation.isPending, + isPending: resetMutation.isPending || validateMutation.isPending, error: resetMutation.error, reset: resetMutation.reset }; diff --git a/rsconcept/frontend/src/backend/library/useApplyLibraryFilter.tsx b/rsconcept/frontend/src/backend/library/useApplyLibraryFilter.tsx index 4281e2ef..0ff93baf 100644 --- a/rsconcept/frontend/src/backend/library/useApplyLibraryFilter.tsx +++ b/rsconcept/frontend/src/backend/library/useApplyLibraryFilter.tsx @@ -1,4 +1,4 @@ -import { useAuth } from '@/backend/auth/useAuth'; +import { useAuthSuspense } from '@/backend/auth/useAuth'; import { matchLibraryItem, matchLibraryItemLocation } from '@/models/libraryAPI'; import { ILibraryFilter } from '@/models/miscellaneous'; @@ -6,7 +6,7 @@ import { useLibrary } from './useLibrary'; export function useApplyLibraryFilter(filter: ILibraryFilter) { const { items } = useLibrary(); - const { user } = useAuth(); + const { user } = useAuthSuspense(); let result = items; if (!filter.folderMode && filter.head) { @@ -28,10 +28,10 @@ export function useApplyLibraryFilter(filter: ILibraryFilter) { result = result.filter(item => filter.isVisible === item.visible); } if (filter.isOwned !== undefined) { - result = result.filter(item => filter.isOwned === (item.owner === user?.id)); + result = result.filter(item => filter.isOwned === (item.owner === user.id)); } if (filter.isEditor !== undefined) { - result = result.filter(item => filter.isEditor == user?.editor.includes(item.id)); + result = result.filter(item => filter.isEditor == user.editor.includes(item.id)); } if (filter.filterUser !== undefined) { result = result.filter(item => filter.filterUser === item.owner); diff --git a/rsconcept/frontend/src/components/wrap/ExpectedAnonymous.tsx b/rsconcept/frontend/src/components/ExpectedAnonymous.tsx similarity index 88% rename from rsconcept/frontend/src/components/wrap/ExpectedAnonymous.tsx rename to rsconcept/frontend/src/components/ExpectedAnonymous.tsx index fea37fa5..d0720a35 100644 --- a/rsconcept/frontend/src/components/wrap/ExpectedAnonymous.tsx +++ b/rsconcept/frontend/src/components/ExpectedAnonymous.tsx @@ -1,11 +1,11 @@ import { useConceptNavigation } from '@/app/Navigation/NavigationContext'; import { urls } from '@/app/urls'; -import { useAuth } from '@/backend/auth/useAuth'; +import { useAuthSuspense } from '@/backend/auth/useAuth'; import { useLogout } from '@/backend/auth/useLogout'; import TextURL from '@/components/ui/TextURL'; function ExpectedAnonymous() { - const { user } = useAuth(); + const { user } = useAuthSuspense(); const { logout } = useLogout(); const router = useConceptNavigation(); @@ -15,7 +15,7 @@ function ExpectedAnonymous() { return (
-

{`Вы вошли в систему как ${user?.username ?? ''}`}

+

{`Вы вошли в систему как ${user.username}`}

| diff --git a/rsconcept/frontend/src/components/wrap/RequireAuth.tsx b/rsconcept/frontend/src/components/RequireAuth.tsx similarity index 100% rename from rsconcept/frontend/src/components/wrap/RequireAuth.tsx rename to rsconcept/frontend/src/components/RequireAuth.tsx diff --git a/rsconcept/frontend/src/components/wrap/DataLoader.tsx b/rsconcept/frontend/src/components/wrap/DataLoader.tsx deleted file mode 100644 index 4eb2d81f..00000000 --- a/rsconcept/frontend/src/components/wrap/DataLoader.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import InfoError, { ErrorData } from '@/components/info/InfoError'; -import Loader from '@/components/ui/Loader'; - -interface DataLoaderProps { - isLoading?: boolean; - error?: ErrorData; - hasNoData?: boolean; -} - -function DataLoader({ isLoading, hasNoData, error, children }: React.PropsWithChildren) { - if (isLoading) { - return ; - } - if (error) { - return ; - } - - if (hasNoData) { - return
Данные не загружены
; - } else { - return <>{children}; - } -} - -export default DataLoader; diff --git a/rsconcept/frontend/src/dialogs/DlgCloneLibraryItem.tsx b/rsconcept/frontend/src/dialogs/DlgCloneLibraryItem.tsx index 6649596b..4688119f 100644 --- a/rsconcept/frontend/src/dialogs/DlgCloneLibraryItem.tsx +++ b/rsconcept/frontend/src/dialogs/DlgCloneLibraryItem.tsx @@ -5,7 +5,7 @@ import { useState } from 'react'; import { useConceptNavigation } from '@/app/Navigation/NavigationContext'; import { urls } from '@/app/urls'; -import { useAuth } from '@/backend/auth/useAuth'; +import { useAuthSuspense } from '@/backend/auth/useAuth'; import { IRSFormCloneDTO } from '@/backend/library/api'; import { useCloneItem } from '@/backend/library/useCloneItem'; import { VisibilityIcon } from '@/components/DomainIcons'; @@ -35,7 +35,7 @@ function DlgCloneLibraryItem() { state => state.props as DlgCloneLibraryItemProps ); const router = useConceptNavigation(); - const { user } = useAuth(); + const { user } = useAuthSuspense(); const [title, setTitle] = useState(cloneTitle(base)); const [alias, setAlias] = useState(base.alias); diff --git a/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/DlgInlineSynthesis.tsx b/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/DlgInlineSynthesis.tsx index 80f38f68..8930787d 100644 --- a/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/DlgInlineSynthesis.tsx +++ b/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/DlgInlineSynthesis.tsx @@ -1,11 +1,12 @@ 'use client'; import clsx from 'clsx'; -import { useEffect, useState } from 'react'; +import { Suspense, useEffect, useState } from 'react'; import { TabList, TabPanel, Tabs } from 'react-tabs'; import { IInlineSynthesisDTO } from '@/backend/rsform/api'; import { useRSForm } from '@/backend/rsform/useRSForm'; +import Loader from '@/components/ui/Loader'; import Modal from '@/components/ui/Modal'; import TabLabel from '@/components/ui/TabLabel'; import { LibraryItemID } from '@/models/library'; @@ -14,7 +15,7 @@ import { ConstituentaID, IRSForm } from '@/models/rsform'; import { useDialogsStore } from '@/stores/dialogs'; import TabConstituents from './TabConstituents'; -import TabSchema from './TabSchema'; +import TabSource from './TabSource'; import TabSubstitutions from './TabSubstitutions'; export interface DlgInlineSynthesisProps { @@ -32,20 +33,20 @@ function DlgInlineSynthesis() { const { receiver, onInlineSynthesis } = useDialogsStore(state => state.props as DlgInlineSynthesisProps); const [activeTab, setActiveTab] = useState(TabID.SCHEMA); - const [donorID, setDonorID] = useState(undefined); + const [sourceID, setSourceID] = useState(undefined); const [selected, setSelected] = useState([]); const [substitutions, setSubstitutions] = useState([]); - const source = useRSForm({ itemID: donorID }); + const { schema } = useRSForm({ itemID: sourceID }); - const validated = !!source.schema && selected.length > 0; + const validated = selected.length > 0; function handleSubmit() { - if (!source.schema) { + if (!sourceID || selected.length === 0) { return; } onInlineSynthesis({ - source: source.schema.id, + source: sourceID, receiver: receiver.id, items: selected, substitutions: substitutions @@ -53,9 +54,16 @@ function DlgInlineSynthesis() { } useEffect(() => { - setSelected(source.schema ? source.schema.items.map(cst => cst.id) : []); + if (schema) { + setSelected(schema.items.map(cst => cst.id)); + } + }, [schema, setSelected]); + + function handleSetSource(schemaID: LibraryItemID) { + setSourceID(schemaID); + setSelected([]); setSubstitutions([]); - }, [source.schema]); + } return ( - - + + - + - + {!!sourceID ? ( + }> + + + ) : null} - + {!!sourceID ? ( + }> + + + ) : null} diff --git a/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/TabConstituents.tsx b/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/TabConstituents.tsx index a75d567d..6f67efa3 100644 --- a/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/TabConstituents.tsx +++ b/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/TabConstituents.tsx @@ -1,33 +1,29 @@ 'use client'; -import { ErrorData } from '@/components/info/InfoError'; +import { useRSFormSuspense } from '@/backend/rsform/useRSForm'; import PickMultiConstituenta from '@/components/select/PickMultiConstituenta'; -import DataLoader from '@/components/wrap/DataLoader'; -import { ConstituentaID, IRSForm } from '@/models/rsform'; +import { LibraryItemID } from '@/models/library'; +import { ConstituentaID } from '@/models/rsform'; import { prefixes } from '@/utils/constants'; interface TabConstituentsProps { - schema?: IRSForm; - loading?: boolean; - error?: ErrorData; + itemID: LibraryItemID; selected: ConstituentaID[]; setSelected: React.Dispatch>; } -function TabConstituents({ schema, error, loading, selected, setSelected }: TabConstituentsProps) { +function TabConstituents({ itemID, selected, setSelected }: TabConstituentsProps) { + const { schema } = useRSFormSuspense({ itemID }); + return ( - - {schema ? ( - - ) : null} - + ); } diff --git a/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/TabSchema.tsx b/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/TabSource.tsx similarity index 91% rename from rsconcept/frontend/src/dialogs/DlgInlineSynthesis/TabSchema.tsx rename to rsconcept/frontend/src/dialogs/DlgInlineSynthesis/TabSource.tsx index b4e604e3..13176cc2 100644 --- a/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/TabSchema.tsx +++ b/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/TabSource.tsx @@ -7,13 +7,13 @@ import { LibraryItemID, LibraryItemType } from '@/models/library'; import { IRSForm } from '@/models/rsform'; import { sortItemsForInlineSynthesis } from '@/models/rsformAPI'; -interface TabSchemaProps { +interface TabSourceProps { selected?: LibraryItemID; setSelected: (newValue: LibraryItemID) => void; receiver: IRSForm; } -function TabSchema({ selected, receiver, setSelected }: TabSchemaProps) { +function TabSource({ selected, receiver, setSelected }: TabSourceProps) { const { items: libraryItems } = useLibrary(); const selectedInfo = libraryItems.find(item => item.id === selected); const sortedItems = sortItemsForInlineSynthesis(receiver, libraryItems); @@ -43,4 +43,4 @@ function TabSchema({ selected, receiver, setSelected }: TabSchemaProps) { ); } -export default TabSchema; +export default TabSource; diff --git a/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/TabSubstitutions.tsx b/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/TabSubstitutions.tsx index 825e1434..fa25b42a 100644 --- a/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/TabSubstitutions.tsx +++ b/rsconcept/frontend/src/dialogs/DlgInlineSynthesis/TabSubstitutions.tsx @@ -1,48 +1,34 @@ 'use client'; -import { ErrorData } from '@/components/info/InfoError'; +import { useRSFormSuspense } from '@/backend/rsform/useRSForm'; import PickSubstitutions from '@/components/select/PickSubstitutions'; -import DataLoader from '@/components/wrap/DataLoader'; +import { LibraryItemID } from '@/models/library'; import { ICstSubstitute } from '@/models/oss'; import { ConstituentaID, IRSForm } from '@/models/rsform'; import { prefixes } from '@/utils/constants'; interface TabSubstitutionsProps { - receiver?: IRSForm; - source?: IRSForm; + receiver: IRSForm; + sourceID: LibraryItemID; selected: ConstituentaID[]; - loading?: boolean; - error?: ErrorData; - substitutions: ICstSubstitute[]; setSubstitutions: React.Dispatch>; } -function TabSubstitutions({ - source, - receiver, - selected, - - error, - loading, - - substitutions, - setSubstitutions -}: TabSubstitutionsProps) { +function TabSubstitutions({ sourceID, receiver, selected, substitutions, setSubstitutions }: TabSubstitutionsProps) { + const { schema: source } = useRSFormSuspense({ itemID: sourceID }); const schemas = [...(source ? [source] : []), ...(receiver ? [receiver] : [])]; return ( - - cst.id !== source?.id || selected.includes(cst.id)} - /> - + cst.id !== source?.id || selected.includes(cst.id)} + /> ); } diff --git a/rsconcept/frontend/src/dialogs/DlgRelocateConstituents.tsx b/rsconcept/frontend/src/dialogs/DlgRelocateConstituents.tsx index 75077fa4..4fc5b324 100644 --- a/rsconcept/frontend/src/dialogs/DlgRelocateConstituents.tsx +++ b/rsconcept/frontend/src/dialogs/DlgRelocateConstituents.tsx @@ -9,9 +9,9 @@ import { useRSForm } from '@/backend/rsform/useRSForm'; import { RelocateUpIcon } from '@/components/DomainIcons'; import PickMultiConstituenta from '@/components/select/PickMultiConstituenta'; import SelectLibraryItem from '@/components/select/SelectLibraryItem'; +import Loader from '@/components/ui/Loader'; import MiniButton from '@/components/ui/MiniButton'; import Modal from '@/components/ui/Modal'; -import DataLoader from '@/components/wrap/DataLoader'; import { ILibraryItem, LibraryItemID } from '@/models/library'; import { HelpTopic } from '@/models/miscellaneous'; import { IOperation, IOperationSchema } from '@/models/oss'; @@ -119,19 +119,18 @@ function DlgRelocateConstituents() { onSelectValue={handleSelectDestination} />
- - {sourceData.schema ? ( - - ) : null} - + {sourceData.isLoading ? : null} + {!sourceData.isLoading && sourceData.schema ? ( + + ) : null}
); diff --git a/rsconcept/frontend/src/pages/CreateItemPage/CreateItemPage.tsx b/rsconcept/frontend/src/pages/CreateItemPage/CreateItemPage.tsx index a5b34b08..44ae148f 100644 --- a/rsconcept/frontend/src/pages/CreateItemPage/CreateItemPage.tsx +++ b/rsconcept/frontend/src/pages/CreateItemPage/CreateItemPage.tsx @@ -1,4 +1,4 @@ -import RequireAuth from '@/components/wrap/RequireAuth'; +import RequireAuth from '@/components/RequireAuth'; import FormCreateItem from './FormCreateItem'; diff --git a/rsconcept/frontend/src/pages/CreateItemPage/FormCreateItem.tsx b/rsconcept/frontend/src/pages/CreateItemPage/FormCreateItem.tsx index f6c4e880..41381168 100644 --- a/rsconcept/frontend/src/pages/CreateItemPage/FormCreateItem.tsx +++ b/rsconcept/frontend/src/pages/CreateItemPage/FormCreateItem.tsx @@ -5,7 +5,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'; import { useConceptNavigation } from '@/app/Navigation/NavigationContext'; import { urls } from '@/app/urls'; -import { useAuth } from '@/backend/auth/useAuth'; +import { useAuthSuspense } from '@/backend/auth/useAuth'; import { ILibraryCreateDTO } from '@/backend/library/api'; import { useCreateItem } from '@/backend/library/useCreateItem'; import { VisibilityIcon } from '@/components/DomainIcons'; @@ -29,7 +29,7 @@ import { EXTEOR_TRS_FILE } from '@/utils/constants'; function FormCreateItem() { const router = useConceptNavigation(); - const { user } = useAuth(); + const { user } = useAuthSuspense(); const { createItem, isPending, error, reset } = useCreateItem(); const searchLocation = useLibrarySearchStore(state => state.location); diff --git a/rsconcept/frontend/src/pages/LibraryPage/ViewSideLocation.tsx b/rsconcept/frontend/src/pages/LibraryPage/ViewSideLocation.tsx index fc001449..70f00328 100644 --- a/rsconcept/frontend/src/pages/LibraryPage/ViewSideLocation.tsx +++ b/rsconcept/frontend/src/pages/LibraryPage/ViewSideLocation.tsx @@ -1,7 +1,7 @@ import clsx from 'clsx'; import { toast } from 'react-toastify'; -import { useAuth } from '@/backend/auth/useAuth'; +import { useAuthSuspense } from '@/backend/auth/useAuth'; import { useLibrary } from '@/backend/library/useLibrary'; import { SubfoldersIcon } from '@/components/DomainIcons'; import { IconFolderEdit, IconFolderTree } from '@/components/Icons'; @@ -23,7 +23,7 @@ interface ViewSideLocationProps { } function ViewSideLocation({ isVisible, onRenameLocation }: ViewSideLocationProps) { - const { user, isAnonymous } = useAuth(); + const { user, isAnonymous } = useAuthSuspense(); const { items } = useLibrary(); const windowSize = useWindowSize(); diff --git a/rsconcept/frontend/src/pages/LoginPage.tsx b/rsconcept/frontend/src/pages/LoginPage.tsx index a2e6c82f..27ac48e2 100644 --- a/rsconcept/frontend/src/pages/LoginPage.tsx +++ b/rsconcept/frontend/src/pages/LoginPage.tsx @@ -6,13 +6,13 @@ import { useEffect, useState } from 'react'; import { useConceptNavigation } from '@/app/Navigation/NavigationContext'; import { urls } from '@/app/urls'; -import { useAuth } from '@/backend/auth/useAuth'; +import { useAuthSuspense } from '@/backend/auth/useAuth'; import { useLogin } from '@/backend/auth/useLogin'; +import ExpectedAnonymous from '@/components/ExpectedAnonymous'; import InfoError, { ErrorData } from '@/components/info/InfoError'; import SubmitButton from '@/components/ui/SubmitButton'; import TextInput from '@/components/ui/TextInput'; import TextURL from '@/components/ui/TextURL'; -import ExpectedAnonymous from '@/components/wrap/ExpectedAnonymous'; import useQueryStrings from '@/hooks/useQueryStrings'; import { resources } from '@/utils/constants'; @@ -21,7 +21,7 @@ function LoginPage() { const query = useQueryStrings(); const userQuery = query.get('username'); - const { isAnonymous } = useAuth(); + const { isAnonymous } = useAuthSuspense(); const { login, isPending, error, reset } = useLogin(); const [username, setUsername] = useState(userQuery || ''); diff --git a/rsconcept/frontend/src/pages/OssPage/DlgChangeLocation.tsx b/rsconcept/frontend/src/pages/OssPage/DlgChangeLocation.tsx index fda2dcd4..404528fd 100644 --- a/rsconcept/frontend/src/pages/OssPage/DlgChangeLocation.tsx +++ b/rsconcept/frontend/src/pages/OssPage/DlgChangeLocation.tsx @@ -3,7 +3,7 @@ import clsx from 'clsx'; import { useState } from 'react'; -import { useAuth } from '@/backend/auth/useAuth'; +import { useAuthSuspense } from '@/backend/auth/useAuth'; import SelectLocationContext from '@/components/select/SelectLocationContext'; import SelectLocationHead from '@/components/select/SelectLocationHead'; import Label from '@/components/ui/Label'; @@ -21,7 +21,7 @@ export interface DlgChangeLocationProps { function DlgChangeLocation() { const { initial, onChangeLocation } = useDialogsStore(state => state.props as DlgChangeLocationProps); - const { user } = useAuth(); + const { user } = useAuthSuspense(); const [head, setHead] = useState(initial.substring(0, 2) as LocationHead); const [body, setBody] = useState(initial.substring(3)); diff --git a/rsconcept/frontend/src/pages/PasswordChangePage.tsx b/rsconcept/frontend/src/pages/PasswordChangePage.tsx index e6f01b27..f4d36b92 100644 --- a/rsconcept/frontend/src/pages/PasswordChangePage.tsx +++ b/rsconcept/frontend/src/pages/PasswordChangePage.tsx @@ -9,9 +9,9 @@ import { urls } from '@/app/urls'; import { IResetPasswordDTO } from '@/backend/auth/api'; import { useResetPassword } from '@/backend/auth/useResetPassword'; import InfoError, { ErrorData } from '@/components/info/InfoError'; +import Loader from '@/components/ui/Loader'; import SubmitButton from '@/components/ui/SubmitButton'; import TextInput from '@/components/ui/TextInput'; -import DataLoader from '@/components/wrap/DataLoader'; import useQueryStrings from '@/hooks/useQueryStrings'; function PasswordChangePage() { @@ -51,43 +51,48 @@ function PasswordChangePage() { validateToken({ token: token ?? '' }, () => setIsTokenValid(true)); }, [token, validateToken]); - return ( - -
- { - setNewPassword(event.target.value); - }} - /> - { - setNewPasswordRepeat(event.target.value); - }} - /> + if (error) { + return ; + } - - {error ? : null} - -
+ if (isPending || !isTokenValid) { + return ; + } + + return ( +
+ { + setNewPassword(event.target.value); + }} + /> + { + setNewPasswordRepeat(event.target.value); + }} + /> + + + ); } diff --git a/rsconcept/frontend/src/pages/RegisterPage/RegisterPage.tsx b/rsconcept/frontend/src/pages/RegisterPage/RegisterPage.tsx index bb5a0bb2..9712e1bb 100644 --- a/rsconcept/frontend/src/pages/RegisterPage/RegisterPage.tsx +++ b/rsconcept/frontend/src/pages/RegisterPage/RegisterPage.tsx @@ -1,15 +1,11 @@ -import { useAuth } from '@/backend/auth/useAuth'; -import Loader from '@/components/ui/Loader'; -import ExpectedAnonymous from '@/components/wrap/ExpectedAnonymous'; +import { useAuthSuspense } from '@/backend/auth/useAuth'; +import ExpectedAnonymous from '@/components/ExpectedAnonymous'; import FormSignup from './FormSignup'; function RegisterPage() { - const { user, isLoading } = useAuth(); + const { user } = useAuthSuspense(); - if (isLoading) { - return ; - } if (user) { return ; } else { diff --git a/rsconcept/frontend/src/pages/UserProfilePage/UserProfilePage.tsx b/rsconcept/frontend/src/pages/UserProfilePage/UserProfilePage.tsx index bd63b0a1..693b5aec 100644 --- a/rsconcept/frontend/src/pages/UserProfilePage/UserProfilePage.tsx +++ b/rsconcept/frontend/src/pages/UserProfilePage/UserProfilePage.tsx @@ -1,7 +1,4 @@ -import { Suspense } from 'react'; - -import Loader from '@/components/ui/Loader'; -import RequireAuth from '@/components/wrap/RequireAuth'; +import RequireAuth from '@/components/RequireAuth'; import EditorPassword from './EditorPassword'; import EditorProfile from './EditorProfile'; @@ -9,15 +6,13 @@ import EditorProfile from './EditorProfile'; function UserProfilePage() { return ( - }> -
-

Учетные данные пользователя

-
- - -
+
+

Учетные данные пользователя

+
+ +
- +
); }