diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 96fec6984..cc31f89e8 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -40,7 +40,6 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "react-i18next": "^15.0.1", - "react-loading-skeleton": "^3.5.0", "react-router-dom": "^7.2.0", "sse.js": "^2.5.0", "use-debounce": "^10.0.1" diff --git a/packages/frontend/src/App.tsx b/packages/frontend/src/App.tsx index a2061d66d..ec8331388 100644 --- a/packages/frontend/src/App.tsx +++ b/packages/frontend/src/App.tsx @@ -1,7 +1,7 @@ import { Navigate, Route, Routes } from 'react-router-dom'; import { ProtectedPageLayout } from './components/PageLayout/PageLayout.tsx'; +import { DialogDetailsPage } from './pages/DialogDetailsPage'; import { Inbox } from './pages/Inbox'; -import { InboxItemPage } from './pages/InboxItemPage'; import { Logout } from './pages/LogoutPage'; import { SavedSearchesPage } from './pages/SavedSearches'; import { PageRoutes } from './pages/routes.ts'; @@ -18,7 +18,7 @@ function App() { } /> } /> } /> - } /> + } /> } /> } /> diff --git a/packages/frontend/src/api/useDialogById.tsx b/packages/frontend/src/api/useDialogById.tsx index 12ca2f0c7..e775313af 100644 --- a/packages/frontend/src/api/useDialogById.tsx +++ b/packages/frontend/src/api/useDialogById.tsx @@ -14,7 +14,7 @@ import { } from 'bff-types-generated'; import { AttachmentUrlConsumer } from 'bff-types-generated'; import { t } from 'i18next'; -import type { DialogActionProps } from '../components/InboxItem/InboxItemDetail.tsx'; +import type { DialogActionProps } from '../components/DialogDetails/DialogDetails.tsx'; import { QUERY_KEYS } from '../constants/queryKeys.ts'; import { type ValueType, getPreferredPropertyByLocale } from '../i18n/property.ts'; import { useOrganizations } from '../pages/Inbox/useOrganizations.ts'; diff --git a/packages/frontend/src/components/InboxItem/InboxItemDetail.tsx b/packages/frontend/src/components/DialogDetails/DialogDetails.tsx similarity index 62% rename from packages/frontend/src/components/InboxItem/InboxItemDetail.tsx rename to packages/frontend/src/components/DialogDetails/DialogDetails.tsx index a9bdb9c33..cd92f6678 100644 --- a/packages/frontend/src/components/InboxItem/InboxItemDetail.tsx +++ b/packages/frontend/src/components/DialogDetails/DialogDetails.tsx @@ -8,6 +8,7 @@ import { type DialogButtonPriority, DialogHeader, } from '@altinn/altinn-components'; +import { DialogStatus } from 'bff-types-generated'; import { type ReactElement, useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { DialogActivity, DialogByIdDetails, DialogTransmission } from '../../api/useDialogById.tsx'; @@ -18,10 +19,11 @@ import { Activity } from '../Activity'; import { AdditionalInfoContent } from '../AdditonalInfoContent'; import { MainContentReference } from '../MainContentReference'; import { Transmission } from '../Transmission'; -import styles from './inboxItemDetail.module.css'; +import styles from './dialogDetails.module.css'; -interface InboxItemDetailProps { +interface DialogDetailsProps { dialog: DialogByIdDetails | undefined | null; + isLoading?: boolean; } /** @@ -94,45 +96,45 @@ const handleDialogActionClick = async ( } }; -export const InboxItemDetail = ({ dialog }: InboxItemDetailProps): ReactElement => { +export const DialogDetails = ({ dialog, isLoading }: DialogDetailsProps): ReactElement => { const { t } = useTranslation(); + const [actionIdLoading, setActionIdLoading] = useState(''); const format = useFormat(); - if (!dialog) { + if (isLoading) { return ( -
-
-
-

{t('error.dialog.not_found')}

-
-

{t('dialog.error_message')}

-
-
+
+ + +
); } - const { - dueAt, - title, - dialogToken, - summary, - sender, - receiver, - guiActions, - additionalInfo, - attachments, - mainContentReference, - activities, - transmissions, - updatedAt, - status, - seenByLabel, - isSeenByEndUser, - seenByOthersCount, - } = dialog; + if (!dialog) { + return ( +
+
+

{t('error.dialog.not_found')}

+
+

{t('dialog.error_message')}

+
+ ); + } - const attachmentCount = attachments.reduce((count, { urls }) => count + urls.length, 0); - const attachmentItems: AttachmentLinkProps[] = attachments.flatMap((attachment) => + const attachmentCount = dialog.attachments.reduce((count, { urls }) => count + urls.length, 0); + const attachmentItems: AttachmentLinkProps[] = dialog.attachments.flatMap((attachment) => attachment.urls.map((url) => ({ label: getPreferredPropertyByLocale(attachment.displayName)?.value || url.url, href: url.url, @@ -140,37 +142,48 @@ export const InboxItemDetail = ({ dialog }: InboxItemDetailProps): ReactElement ); const clockPrefix = t('word.clock_prefix'); const formatString = clockPrefix ? `do MMMM yyyy '${clockPrefix}' HH.mm` : `do MMMM yyyy HH.mm`; - const dueAtLabel = dueAt ? format(dueAt, formatString) : ''; - - const [isLoading, setIsLoading] = useState(''); + const dueAtLabel = dialog.dueAt ? format(dialog.dueAt, formatString) : ''; - const dialogActions: DialogActionButtonProps[] = guiActions.map((action) => ({ + const dialogActions: DialogActionButtonProps[] = dialog.guiActions.map((action) => ({ id: action.id, label: action.title, disabled: !!isLoading || action.disabled, priority: action.priority.toLocaleLowerCase() as DialogButtonPriority, url: action.url, httpMethod: action.httpMethod, - loading: isLoading === action.id, + loading: actionIdLoading === action.id, onClick: () => { - setIsLoading(action.id); - handleDialogActionClick(action, dialogToken, () => setIsLoading('')); + setActionIdLoading(action.id); + void handleDialogActionClick(action, dialog.dialogToken, () => setActionIdLoading('')); }, })); return (
- + -

{summary}

- +

{dialog.summary}

+ {attachmentCount > 0 && (
- - {activities.length > 0 && ( + + {dialog.activities.length > 0 && (

{t('word.activities')}

- {activities.map((activity: DialogActivity) => ( - + {dialog.activities.map((activity: DialogActivity) => ( + ))}
)} - {transmissions.length > 0 && ( + {dialog.transmissions.length > 0 && (

{t('word.transmissions')}

- {transmissions.map((transmission: DialogTransmission) => ( + {dialog.transmissions.map((transmission: DialogTransmission) => ( ))}
diff --git a/packages/frontend/src/components/DialogDetails/dialogDetails.module.css b/packages/frontend/src/components/DialogDetails/dialogDetails.module.css new file mode 100644 index 000000000..4a657bbef --- /dev/null +++ b/packages/frontend/src/components/DialogDetails/dialogDetails.module.css @@ -0,0 +1,35 @@ +.summarySection { + display: flex; + flex-direction: column; + row-gap: 0.25rem; +} + +.header { + display: flex; + font-size: 1.5rem; + align-items: center; +} + +.title { + color: #000; + font-weight: 500; + font-size: 1.5rem; + line-height: 1.25; + margin-top: 0; +} + +.activities, +.transmissions { + display: flex; + flex-direction: column; + row-gap: 1.5rem; + border-top: 1px solid rgba(0, 0, 0, 0.2); + padding: 1.5rem 0; +} + +.activitiesTitle, +.transmissionsTitle { + font-size: 1.25rem; + font-weight: 500; + margin: 0; +} diff --git a/packages/frontend/src/components/DialogDetails/index.ts b/packages/frontend/src/components/DialogDetails/index.ts new file mode 100644 index 000000000..28e133a3e --- /dev/null +++ b/packages/frontend/src/components/DialogDetails/index.ts @@ -0,0 +1 @@ +export * from './DialogDetails.tsx'; diff --git a/packages/frontend/src/components/InboxItem/InboxItems.tsx b/packages/frontend/src/components/InboxItem/InboxItems.tsx deleted file mode 100644 index 9bfffcf9c..000000000 --- a/packages/frontend/src/components/InboxItem/InboxItems.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { ReactElement } from 'react'; -import styles from './inboxItems.module.css'; - -interface InboxItemsProps { - children: React.ReactNode; -} - -/** - * A container component for displaying a list of inbox items. It serves as a wrapper - * for individual `InboxItem` components, ensuring they are styled and organized collectively. - * This component primarily handles the layout of its children inbox items. - * - * @component - * @param {Object} props - The properties passed to the component. - * @param {React.ReactNode} props.children - The child components to be rendered within the container. - * Typically, these are `InboxItem` components, but can include any React nodes. - * @returns {ReactElement} A div element wrapping the children in a styled manner, - * according to the `inboxItems` CSS class defined in `inboxItems.module.css`. - * - */ - -export const InboxItems = ({ children }: InboxItemsProps): ReactElement => { - return
    {children}
; -}; diff --git a/packages/frontend/src/components/InboxItem/InboxItemsHeader.tsx b/packages/frontend/src/components/InboxItem/InboxItemsHeader.tsx deleted file mode 100644 index a515790c8..000000000 --- a/packages/frontend/src/components/InboxItem/InboxItemsHeader.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Button } from '@digdir/designsystemet-react'; -import { CheckmarkIcon } from '@navikt/aksel-icons'; -import { useTranslation } from 'react-i18next'; -import { FeatureFlagKeys, useFeatureFlag } from '../../featureFlags'; -import styles from './inboxItemsHeader.module.css'; - -interface InboxItemsHeaderProps { - title: string; - onSelectAll?: () => void; - hideSelectAll?: boolean; -} - -/** - * `InboxItemsHeader` renders the header section of an inbox items list, including a title and an optional "Select All" button. - * - * @component - * @example - * const title = "Inbox" - * const onSelectAll = () => console.log("All items selected") - * return - * - * @param {Object} props - Props for InboxItemsHeader - * @param {string} props.title - The title to be displayed in the header. - * @param {boolean} props.hideSelectAll - Optionally hide the select all button. - * @param {Function} [props.onSelectAll] - Optional callback function to be called when the "Select All" button is clicked. - */ -export const InboxItemsHeader = ({ title, onSelectAll, hideSelectAll = false }: InboxItemsHeaderProps) => { - const { t } = useTranslation(); - const disableBulkActions = useFeatureFlag(FeatureFlagKeys.DisableBulkActions); - return ( -
-

{title}

- {typeof onSelectAll === 'function' && !disableBulkActions && !hideSelectAll && ( - - )} -
- ); -}; diff --git a/packages/frontend/src/components/InboxItem/inboxItemDetail.module.css b/packages/frontend/src/components/InboxItem/inboxItemDetail.module.css deleted file mode 100644 index 612b5b496..000000000 --- a/packages/frontend/src/components/InboxItem/inboxItemDetail.module.css +++ /dev/null @@ -1,155 +0,0 @@ -.errorFallBack { - margin-top: 1rem; - padding: 1rem; -} - -.summarySection { - display: flex; - flex-direction: column; - row-gap: 0.25rem; -} - -.header { - display: flex; - font-size: 1.5rem; - align-items: center; -} - -.title { - color: #000; - font-weight: 500; - font-size: 1.5rem; - line-height: 1.25; - margin-top: 0; -} - -.icon { - margin-right: 0.375rem; - height: 18px; - width: 18px; - flex-shrink: 0; -} - -.activities, -.transmissions { - display: flex; - flex-direction: column; - row-gap: 1.5rem; - border-top: 1px solid rgba(0, 0, 0, 0.2); - padding: 1.5rem 0; -} - -.activitiesTitle, -.transmissionsTitle { - font-size: 1.25rem; - font-weight: 500; - margin: 0; -} - -.receiver, -.sender { - font-size: 1rem; - align-items: center; - white-space: nowrap; -} - -.receiver { - color: var(--text-neutral-subtle); -} - -.sender { - font-weight: 500; -} - -.participantIcon { - margin-right: 0.375em; - height: 36px; - width: 36px; - flex-shrink: 0; - > svg, - img { - min-width: 100%; - min-height: 100%; - max-width: 36px; - max-height: 36px; - } -} - -.icon { - margin-right: 0.5rem; - height: 36px; - width: 36px; - flex-shrink: 0; - > svg { - min-width: 100%; - min-height: 100%; - } -} - -.tags { - font-size: 0.875rem; - display: flex; - flex-direction: row; - align-items: center; -} - -.tag { - display: flex; - align-items: center; - margin-right: 1rem; - font-weight: 400; - font-size: 1rem; - color: var(--text-neutral-subtle); -} - -.tagIcon { - margin-right: 0.5rem; - height: 20px; - width: 20px; - flex-shrink: 0; - > svg { - min-width: 100%; - min-height: 100%; - } -} - -.attachments { - list-style: none; - padding: 0; - margin: 0; - display: flex; - flex-direction: column; - gap: 0.5rem; -} - -.attachmentItem { - list-style-type: none; - margin: 0; - line-height: 1.5; - display: flex; - align-items: center; - color: var(--text-accent-subtle); - font-size: 1.125rem; -} - -.attachmentIcon { - --icon-size: 1.6875rem; - min-height: var(--icon-size); - min-width: var(--icon-size); - max-height: var(--icon-size); - max-width: var(--icon-size); - align-self: baseline; -} - -.attachmentItemIcon { - height: 24px; - width: 24px; - margin-right: 1rem; -} - -.attachmentTitle { - color: var(--text-neutral-subtle); - font-weight: 400; - font-size: 1rem; - margin-bottom: 0.5rem; -} diff --git a/packages/frontend/src/components/InboxItem/inboxItems.module.css b/packages/frontend/src/components/InboxItem/inboxItems.module.css deleted file mode 100644 index 67da8de2e..000000000 --- a/packages/frontend/src/components/InboxItem/inboxItems.module.css +++ /dev/null @@ -1,18 +0,0 @@ -.inboxItems { - display: flex; - flex-direction: column; - row-gap: 8px; - list-style: none; - padding-left: 0; -} - -@media screen and (max-width: 1024px) { - .inboxItems { - padding-top: 0; - margin-top: 0; - } - - h2 { - margin-top: 0.5rem; - } -} diff --git a/packages/frontend/src/components/InboxItem/inboxItemsHeader.module.css b/packages/frontend/src/components/InboxItem/inboxItemsHeader.module.css deleted file mode 100644 index e0c3f74ab..000000000 --- a/packages/frontend/src/components/InboxItem/inboxItemsHeader.module.css +++ /dev/null @@ -1,22 +0,0 @@ -.inboxItemsHeader { - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - margin-left: 0; - margin-top: 0; - :first-letter { - text-transform: capitalize; - } -} - -@media screen and (max-width: 1024px) { - .inboxItemsHeader { - margin-left: 1rem; - } -} - -.title { - font-weight: 500; - font-size: 1.25rem; -} diff --git a/packages/frontend/src/components/InboxItem/index.ts b/packages/frontend/src/components/InboxItem/index.ts deleted file mode 100644 index 0b357be69..000000000 --- a/packages/frontend/src/components/InboxItem/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './InboxItems.tsx'; -export * from './InboxItemDetail.tsx'; diff --git a/packages/frontend/src/components/index.ts b/packages/frontend/src/components/index.ts index c39f7d721..f95beeeaa 100644 --- a/packages/frontend/src/components/index.ts +++ b/packages/frontend/src/components/index.ts @@ -1,3 +1,3 @@ -export * from './InboxItem'; +export * from './DialogDetails'; export * from './PageLayout/Footer'; export * from './PageLayout'; diff --git a/packages/frontend/src/pages/InboxItemPage/InboxItemPage.tsx b/packages/frontend/src/pages/DialogDetailsPage/DialogDetailsPage.tsx similarity index 91% rename from packages/frontend/src/pages/InboxItemPage/InboxItemPage.tsx rename to packages/frontend/src/pages/DialogDetailsPage/DialogDetailsPage.tsx index ac835ee55..24179cedc 100644 --- a/packages/frontend/src/pages/InboxItemPage/InboxItemPage.tsx +++ b/packages/frontend/src/pages/DialogDetailsPage/DialogDetailsPage.tsx @@ -15,22 +15,23 @@ import { updateSystemLabel } from '../../api/queries.ts'; import { useDialogById } from '../../api/useDialogById.tsx'; import { useDialogByIdSubscription } from '../../api/useDialogByIdSubscription.ts'; import { useParties } from '../../api/useParties.ts'; -import { InboxItemDetail } from '../../components'; +import { DialogDetails } from '../../components'; import { DialogToolbar } from '../../components/DialogToolbar/DialogToolbar.tsx'; import { QUERY_KEYS } from '../../constants/queryKeys.ts'; -import { InboxItemPageSkeleton } from './InboxItemPageSkeleton.tsx'; -export const InboxItemPage = () => { +export const DialogDetailsPage = () => { const { id } = useParams(); const { parties } = useParties(); const { t } = useTranslation(); const location = useLocation(); - const { dialog, isLoading, isSuccess, isError } = useDialogById(parties, id); + const { dialog, isLoading: isLoadingDialog, isSuccess, isError } = useDialogById(parties, id); const [archiveLoading, setArchiveLoading] = useState(false); const [deleteLoading, setDeleteLoading] = useState(false); const [undoLoading, setUndoLoading] = useState(false); const { openSnackbar } = useSnackbar(); const queryClient = useQueryClient(); + const isLoading = isLoadingDialog || (!isSuccess && !isError); + useDialogByIdSubscription(id, dialog?.dialogToken); const handleMoveDialog = async ({ @@ -108,12 +109,8 @@ export const InboxItemPage = () => { }); }; - if (isLoading || (!isSuccess && !isError)) { - return ; - } - const previousPath = (location?.state?.fromView ?? '/') + location.search; - const showToolbar = id && dialog; + const showToolbar = id && dialog && !isLoading; return (
@@ -127,7 +124,7 @@ export const InboxItemPage = () => { as: (props: LinkProps) => , }} /> - + {showToolbar && ( = ({ - numberOfItems, - withHeader = false, - noBorder = false, -}) => { - const key = useRef('inbox-skeleton' + Math.random()); - - return ( - <> - - {withHeader && ( -
-

- -

-
- )} - {Array.from({ length: numberOfItems }).map((_, index) => ( -
  • -
    -
    -

    - -

    -
    - - -
    -
    - - - -
    - - - -
    - - - -
    -
    -
    -
  • - ))} -
    - - ); -}; diff --git a/packages/frontend/src/pages/Inbox/inboxSkeleton.module.css b/packages/frontend/src/pages/Inbox/inboxSkeleton.module.css deleted file mode 100644 index ba5ffd586..000000000 --- a/packages/frontend/src/pages/Inbox/inboxSkeleton.module.css +++ /dev/null @@ -1,41 +0,0 @@ -.inboxItems { - display: flex; - flex-direction: column; - row-gap: 8px; - list-style: none; - padding-left: 0; -} - -@media screen and (max-width: 1024px) { - .inboxItems { - padding-top: 0; - margin-top: 0; - } - - h2 { - margin-top: 0.5rem; - } -} - -.inboxItemsHeader { - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - margin-left: 0; - margin-top: 0; - :first-letter { - text-transform: capitalize; - } -} - -@media screen and (max-width: 1024px) { - .inboxItemsHeader { - margin-left: 1rem; - } -} - -.title { - font-weight: 500; - font-size: 1.25rem; -} diff --git a/packages/frontend/src/pages/InboxItemPage/InboxItemPageSkeleton.tsx b/packages/frontend/src/pages/InboxItemPage/InboxItemPageSkeleton.tsx deleted file mode 100644 index bca500f7b..000000000 --- a/packages/frontend/src/pages/InboxItemPage/InboxItemPageSkeleton.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import Skeleton from 'react-loading-skeleton'; -import { InboxSkeleton } from '../Inbox/InboxSkeleton'; -import styles from './inboxItemPageSkeleton.module.css'; - -export const InboxItemPageSkeleton = () => { - return ( -
    - - - - - -
    - ); -}; diff --git a/packages/frontend/src/pages/InboxItemPage/inboxItemPageSkeleton.module.css b/packages/frontend/src/pages/InboxItemPage/inboxItemPageSkeleton.module.css deleted file mode 100644 index 39a3cd0fb..000000000 --- a/packages/frontend/src/pages/InboxItemPage/inboxItemPageSkeleton.module.css +++ /dev/null @@ -1,51 +0,0 @@ -.itemInboxPage { - display: flex; - padding: 2rem 1rem; - flex-direction: column; - background: #fff; - box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1); - - @media screen and (min-width: 600px) { - min-width: 550px; - max-width: 988px; - } -} - -@media screen and (max-width: 1024px) { - .itemInboxPage { - margin-top: 1.5rem; - } -} - -.titleOne { - margin-top: 2rem; - margin-left: 1rem; -} - -.subTitle { - margin-left: 1rem; - margin-top: 2rem; -} - -.titleTwo { - margin-left: 1rem; - margin-bottom: 1.5rem; -} - -.backButton { - text-decoration: none; - margin-top: 1rem; - margin-left: 1rem; -} - -.backLink { - display: flex; - align-items: center; - text-decoration: none; - gap: 8px; -} - -.backIcon { - height: 1.5rem; - width: 1.5rem; -} diff --git a/packages/frontend/src/pages/InboxItemPage/index.ts b/packages/frontend/src/pages/InboxItemPage/index.ts deleted file mode 100644 index afc6cf65b..000000000 --- a/packages/frontend/src/pages/InboxItemPage/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { InboxItemPage } from './InboxItemPage.tsx'; diff --git a/packages/frontend/tests/stories/inboxItemPage.spec.ts b/packages/frontend/tests/stories/DialogDetailPage.spec.ts similarity index 97% rename from packages/frontend/tests/stories/inboxItemPage.spec.ts rename to packages/frontend/tests/stories/DialogDetailPage.spec.ts index a58b4ea43..7ae1d553b 100644 --- a/packages/frontend/tests/stories/inboxItemPage.spec.ts +++ b/packages/frontend/tests/stories/DialogDetailPage.spec.ts @@ -3,7 +3,7 @@ import { defaultAppURL } from '../'; import { PageRoutes } from '../../src/pages/routes'; import { getSidebarMenuItem, getSidebarMenuItemBadge } from './common'; -test.describe('InboxItemPage', () => { +test.describe('DialogDetailsPage', () => { test('Check message opening, archiving and deleting', async ({ page }: { page: Page }) => { const archiveLink = getSidebarMenuItem(page, PageRoutes.archive); const archiveLinkCount = archiveLink.locator('span:text("1")'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 466aa823e..35e164625 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -439,9 +439,6 @@ importers: react-i18next: specifier: ^15.0.1 version: 15.4.0(i18next@23.16.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react-loading-skeleton: - specifier: ^3.5.0 - version: 3.5.0(react@19.0.0) react-router-dom: specifier: ^7.2.0 version: 7.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -8578,11 +8575,6 @@ packages: react-loadable: '*' webpack: '>=4.41.1 || 5.x' - react-loading-skeleton@3.5.0: - resolution: {integrity: sha512-gxxSyLbrEAdXTKgfbpBEFZCO/P153DnqSCQau2+o6lNy1jgMRr2MmRmOzMmyrwSaSYLRB8g7b0waYPmUjz7IhQ==} - peerDependencies: - react: '>=16.8.0' - react-router-config@5.1.1: resolution: {integrity: sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==} peerDependencies: @@ -20488,10 +20480,6 @@ snapshots: react-loadable: '@docusaurus/react-loadable@6.0.0(react@19.0.0)' webpack: 5.97.1(@swc/core@1.10.7) - react-loading-skeleton@3.5.0(react@19.0.0): - dependencies: - react: 19.0.0 - react-router-config@5.1.1(react-router@5.3.4(react@19.0.0))(react@19.0.0): dependencies: '@babel/runtime': 7.26.7