From 40ad1ad30b412bc47bb5c605a1dbd8e6a9f8be1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kurczewski?= Date: Thu, 3 Oct 2024 09:33:58 +0200 Subject: [PATCH] [CP-3141] Implemented empty state (#2102) --- .../src/lib/feature/data-provider-config.ts | 7 ++ .../feature/src/lib/generic-view.tsx | 9 +- .../feature/src/lib/setup-component.tsx | 22 +++++ .../lib/use-dev-views/views/contacts-view.ts | 94 ++++++++++++++++++- libs/generic-view/models/src/lib/device.ts | 29 +++--- libs/generic-view/models/src/lib/form.ts | 2 + libs/generic-view/models/src/lib/table.ts | 8 ++ libs/generic-view/store/src/index.ts | 3 + .../store/src/lib/action-names.ts | 4 +- .../store/src/lib/selectors/view.ts | 10 ++ .../store/src/lib/use-form-field.ts | 55 +++++++++++ .../store/src/lib/use-form-register.ts | 43 +++++++++ .../store/src/lib/views/actions.ts | 25 +++-- .../store/src/lib/views/reducer.ts | 50 +++++----- .../ui/src/lib/interactive/form/form.tsx | 7 ++ libs/generic-view/ui/src/lib/table/table.tsx | 11 ++- libs/generic-view/utils/src/index.ts | 1 + .../utils/src/lib/use-current-view-key.ts | 14 +++ 18 files changed, 336 insertions(+), 58 deletions(-) create mode 100644 libs/generic-view/store/src/lib/use-form-field.ts create mode 100644 libs/generic-view/store/src/lib/use-form-register.ts create mode 100644 libs/generic-view/utils/src/lib/use-current-view-key.ts diff --git a/libs/device/models/src/lib/feature/data-provider-config.ts b/libs/device/models/src/lib/feature/data-provider-config.ts index b551139195..afe0d6e82f 100644 --- a/libs/device/models/src/lib/feature/data-provider-config.ts +++ b/libs/device/models/src/lib/feature/data-provider-config.ts @@ -107,10 +107,17 @@ const formFieldsSchema = z.object({ fields: fieldsSchema, }) +const formFieldsSchemaV2 = z.object({ + source: z.literal("form-fields-v2"), + formName: z.string(), + fields: fieldsSchema, +}) + export const dataProviderSchema = z.union([ entitiesArraySchema, entitiesFieldSchema, formFieldsSchema, + formFieldsSchemaV2, ]) export type DataProviderConfig = z.infer diff --git a/libs/generic-view/feature/src/lib/generic-view.tsx b/libs/generic-view/feature/src/lib/generic-view.tsx index 509d4f5902..6f893a9603 100644 --- a/libs/generic-view/feature/src/lib/generic-view.tsx +++ b/libs/generic-view/feature/src/lib/generic-view.tsx @@ -4,22 +4,17 @@ */ import React, { FunctionComponent } from "react" -import { useParams } from "react-router" import { GenericThemeProvider } from "generic-view/theme" import RecursiveLayout from "./recursive-layout" import GenericModals from "./generic-modals" import { useDevConsole } from "./use-dev-console" import { useDevViews } from "./use-dev-views/use-dev-views" import { GenericToasts } from "./generic-toasts" -import { FormsProvider } from "generic-view/utils" +import { FormsProvider, useCurrentViewKey } from "generic-view/utils" export const GenericView: FunctionComponent = () => { useDevConsole() - const { viewKey, subviewKey } = useParams<{ - viewKey: string - subviewKey?: string - }>() - const currentViewKey = subviewKey || viewKey + const currentViewKey = useCurrentViewKey() useDevViews(currentViewKey) return ( diff --git a/libs/generic-view/feature/src/lib/setup-component.tsx b/libs/generic-view/feature/src/lib/setup-component.tsx index dbc53b56f9..2f6d431645 100644 --- a/libs/generic-view/feature/src/lib/setup-component.tsx +++ b/libs/generic-view/feature/src/lib/setup-component.tsx @@ -21,6 +21,7 @@ import { selectEntitiesData, selectEntitiesIdFieldKey, selectEntityData, + useFormField, } from "generic-view/store" import { dataProviderFilter, @@ -80,6 +81,12 @@ export const setupComponent =

( if (dataProvider) return return selectComponentData(state, { viewKey, componentKey }) }) + const formDataV2 = useFormField({ + formName: + dataProvider?.source === "form-fields-v2" + ? dataProvider.formName + : undefined, + }) const entitiesData = useSelector((state: ReduxRootState) => { if (dataProvider?.source !== "entities-array") return @@ -150,6 +157,19 @@ export const setupComponent =

( : formContext.watch(providerField) const value = processFormFields(config, fieldValue) + if (isString(value) && componentField === "dataItemId") { + dataItemId = value + continue + } + set(editableProps || {}, componentField, value) + } + } else if (dataProvider?.source === "form-fields-v2") { + for (const fieldConfig of dataProvider.fields) { + const { componentField, providerField, ...config } = fieldConfig + const value = processFormFields( + config, + formDataV2.getValue(providerField) + ) if (isString(value) && componentField === "dataItemId") { dataItemId = value continue @@ -161,6 +181,7 @@ export const setupComponent =

( const layoutDependency = JSON.stringify(layout) const styleDependency = JSON.stringify(style) const dataProviderDependency = JSON.stringify(dataProvider) + const formDataV2Dependency = JSON.stringify(formDataV2) const styles = useMemo(() => { return setupStyles(style, layout) @@ -226,6 +247,7 @@ export const setupComponent =

( editablePropsDependency, dataProviderDependency, styles, + formDataV2Dependency, ]) } } diff --git a/libs/generic-view/feature/src/lib/use-dev-views/views/contacts-view.ts b/libs/generic-view/feature/src/lib/use-dev-views/views/contacts-view.ts index 0095b2cd79..fa74b479d0 100644 --- a/libs/generic-view/feature/src/lib/use-dev-views/views/contacts-view.ts +++ b/libs/generic-view/feature/src/lib/use-dev-views/views/contacts-view.ts @@ -24,6 +24,12 @@ const view: View = { contactsForm: { component: "form", config: { + defaultValues: { + searchedContact: undefined, + activeContactId: undefined, + selectedContacts: [], + allContacts: [], + }, formOptions: { defaultValues: { searchedContact: undefined, @@ -40,10 +46,88 @@ const view: View = { config: { entitiesTypes: ["contacts"], }, - childrenKeys: ["contactsPanel", "contactsFormWrapper"], + childrenKeys: ["contactsPanelWrapper", "contactsFormWrapper", "emptyListWrapper"], + }, + emptyListWrapper: { + component: "conditional-renderer", + dataProvider: { + source: "form-fields-v2", + formName: "contactsForm", + fields: [ + { + providerField: "allContacts", + componentField: "data.render", + modifier: "length", + condition: "eq", + value: 0, + }, + ], + }, + childrenKeys: ["fullScreenWrapper"], + }, + fullScreenWrapper: { + component: "block-plain", + layout: { + gridPlacement: { + row: 1, + column: 1, + width: 1, + height: 2, + }, + flexLayout: { + rowGap: "24px", + direction: "column", + justifyContent: "center", + alignItems: "center", + }, + }, + // importContactsButton already comes from the device through API + childrenKeys: ["emptyStateIcon", "emptyStateText", "importContactsButton"], + }, + emptyStateIcon: { + component: "modal.titleIcon", + config: { + type: IconType.ContactsBook, + }, + }, + emptyStateText: { + component: "block-plain", + layout: { + flexLayout: { + direction: "column", + alignItems: "center", + rowGap: "8px", + }, + }, + childrenKeys: ["title", "detailText"], + }, + contactsPanelWrapper: { + component: "conditional-renderer", + dataProvider: { + source: "form-fields-v2", + formName: "contactsForm", + fields: [ + { + providerField: "allContacts", + componentField: "data.render", + modifier: "length", + condition: "gt", + value: 0, + }, + ], + }, + childrenKeys: ["contactsPanel"], }, contactsPanel: { component: "block-plain", + layout: { + gridPlacement: { + row: 1, + column: 1, + width: 1, + height: 1, + }, + }, childrenKeys: ["contactsPanelDefaultMode", "contactsPanelSelectMode"], }, contactsPanelDefaultMode: { @@ -403,6 +487,14 @@ const view: View = { selectedIdsFieldName: "selectedContacts", allIdsFieldName: "allContacts", }, + form: { + formName: "contactsForm", + assignFields: { + activeIdFieldName: "activeContactId", + selectedIdsFieldName: "selectedContacts", + allIdsFieldName: "allContacts", + }, + }, }, childrenKeys: [ "columnCheckbox", diff --git a/libs/generic-view/models/src/lib/device.ts b/libs/generic-view/models/src/lib/device.ts index f53139f291..96055219ae 100644 --- a/libs/generic-view/models/src/lib/device.ts +++ b/libs/generic-view/models/src/lib/device.ts @@ -9,20 +9,21 @@ import { DeviceProperties } from "device-manager/models" import { ApiConfig, MenuConfig, OverviewData } from "device/models" import { DeviceId } from "Core/device/constants/device-id" +export interface GenericForm { + fields: Record +} + +interface Feature> { + config?: View + data?: Data + forms?: Record +} + export type Features = { - "mc-overview"?: { - config?: View - data?: OverviewData - } - "mc-about"?: { - config?: View - data?: OverviewData - } + "mc-overview"?: Feature + "mc-about"?: Feature } & { - [key: string]: { - config?: View - data?: Record - } + [key: string]: Feature } export interface DeviceConfiguration { @@ -31,9 +32,7 @@ export interface DeviceConfiguration { features?: Features } -export interface Device - extends DeviceProperties, - Partial { +export interface Device extends DeviceProperties, Partial { id: DeviceId serialNumber: string | undefined deviceType: DeviceType diff --git a/libs/generic-view/models/src/lib/form.ts b/libs/generic-view/models/src/lib/form.ts index cb764f2674..1c4901b526 100644 --- a/libs/generic-view/models/src/lib/form.ts +++ b/libs/generic-view/models/src/lib/form.ts @@ -10,6 +10,7 @@ const dataValidator = z.undefined() interface Config { formOptions?: Pick + defaultValues?: Record } const configValidator: z.ZodType = z @@ -21,6 +22,7 @@ const configValidator: z.ZodType = z reValidateMode: z.enum(["onChange", "onBlur", "onSubmit"]).optional(), defaultValues: z.record(z.string(), z.any()).optional(), }), + defaultValues: z.record(z.string(), z.any()).optional(), }) .optional() diff --git a/libs/generic-view/models/src/lib/table.ts b/libs/generic-view/models/src/lib/table.ts index 4288cf012d..947045cfbe 100644 --- a/libs/generic-view/models/src/lib/table.ts +++ b/libs/generic-view/models/src/lib/table.ts @@ -15,6 +15,14 @@ const configValidator = z.object({ selectedIdsFieldName: z.string().optional(), allIdsFieldName: z.string().optional(), }), + form: z.object({ + formName: z.string(), + assignFields: z.object({ + activeIdFieldName: z.string().optional(), + selectedIdsFieldName: z.string().optional(), + allIdsFieldName: z.string().optional(), + }), + }), columnsNames: z.array(z.string()).optional(), }) diff --git a/libs/generic-view/store/src/index.ts b/libs/generic-view/store/src/index.ts index 652ca287c9..1aec393a46 100644 --- a/libs/generic-view/store/src/index.ts +++ b/libs/generic-view/store/src/index.ts @@ -67,3 +67,6 @@ export * from "./lib/toasts/actions" export * from "./lib/toasts/open-toast.action" export * from "./lib/action-names" + +export * from "./lib/use-form-field" +export * from "./lib/use-form-register" diff --git a/libs/generic-view/store/src/lib/action-names.ts b/libs/generic-view/store/src/lib/action-names.ts index 927995ccad..dbac0d8c57 100644 --- a/libs/generic-view/store/src/lib/action-names.ts +++ b/libs/generic-view/store/src/lib/action-names.ts @@ -10,13 +10,13 @@ export enum ActionName { GetOutboxData = "api-actions/get-outbox-data", SetMenu = "generic-views/set-menu", - SetViewLayout = "generic-views/set-view-layout", - SetViewData = "generic-views/set-view-data", SetLastRefresh = "generic-views/set-last-refresh", AddDevice = "generic-views/add-device", RemoveDevice = "generic-views/remove-device", SetDeviceState = "generic-views/set-device-state", SetGenericConfig = "generic-views/set-generic-config", + RegisterForm = "generic-views/register-form", + SetFormField = "generic-views/set-form-field", OpenModal = "generic-modals/open-modal", CloseModal = "generic-modals/close-modal", diff --git a/libs/generic-view/store/src/lib/selectors/view.ts b/libs/generic-view/store/src/lib/selectors/view.ts index 333f3b27b8..e740adc5aa 100644 --- a/libs/generic-view/store/src/lib/selectors/view.ts +++ b/libs/generic-view/store/src/lib/selectors/view.ts @@ -26,3 +26,13 @@ export const selectViewData = createSelector( selectView, (config) => config?.data ) + +const selectViewForms = createSelector(selectView, (config) => config?.forms) + +export const selectViewForm = createSelector( + selectViewForms, + (state: ReduxRootState, { formName }: { formName: string }) => formName, + (forms, formName) => { + return forms?.[formName] + } +) diff --git a/libs/generic-view/store/src/lib/use-form-field.ts b/libs/generic-view/store/src/lib/use-form-field.ts new file mode 100644 index 0000000000..807819cb12 --- /dev/null +++ b/libs/generic-view/store/src/lib/use-form-field.ts @@ -0,0 +1,55 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { useDispatch, useSelector } from "react-redux" +import { Dispatch, ReduxRootState } from "Core/__deprecated__/renderer/store" +import { selectActiveApiDeviceId } from "./selectors/select-active-api-device-id" +import { selectViewForm } from "./selectors" +import { setFormField } from "./views/actions" +import { get } from "lodash" +import { useCallback } from "react" +import { useCurrentViewKey } from "generic-view/utils" + +interface UseViewForm { + formName?: string +} + +export const useFormField = ({ formName }: UseViewForm) => { + const viewKey = useCurrentViewKey() + const dispatch = useDispatch() + const activeDeviceId = useSelector(selectActiveApiDeviceId) + const form = useSelector((state: ReduxRootState) => { + if (!formName) return undefined + return selectViewForm(state, { formName, viewKey }) + }) + + const getValue = useCallback( + (field: string) => { + return field && form?.fields ? get(form.fields, field) : undefined + }, + [form?.fields] + ) + + const setValue = useCallback( + (field: string, value: unknown) => { + if (!activeDeviceId || !field || !formName) return + dispatch( + setFormField({ + field, + value, + deviceId: activeDeviceId, + feature: viewKey, + formName, + }) + ) + }, + [activeDeviceId, dispatch, formName, viewKey] + ) + + return { + getValue, + setValue, + } +} diff --git a/libs/generic-view/store/src/lib/use-form-register.ts b/libs/generic-view/store/src/lib/use-form-register.ts new file mode 100644 index 0000000000..ba628968e2 --- /dev/null +++ b/libs/generic-view/store/src/lib/use-form-register.ts @@ -0,0 +1,43 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { useDispatch, useSelector } from "react-redux" +import { Dispatch, ReduxRootState } from "Core/__deprecated__/renderer/store" +import { selectActiveApiDeviceId } from "./selectors/select-active-api-device-id" +import { registerForm } from "./views/actions" +import { useEffect } from "react" +import { selectViewForm } from "./selectors" +import { useCurrentViewKey } from "generic-view/utils" + +interface UseViewForm { + formName: string + options?: { + defaultValues?: Record + } +} + +export const useFormRegister = ({ formName, options }: UseViewForm) => { + const viewKey = useCurrentViewKey() + const dispatch = useDispatch() + const activeDeviceId = useSelector(selectActiveApiDeviceId) + const form = useSelector((state: ReduxRootState) => { + return selectViewForm(state, { formName, viewKey }) + }) + + useEffect(() => { + if (!activeDeviceId || form) return + const { defaultValues = {} } = options || {} + dispatch( + registerForm({ + deviceId: activeDeviceId, + feature: viewKey, + formName, + form: { + fields: defaultValues, + }, + }) + ) + }, [activeDeviceId, dispatch, form, formName, options, viewKey]) +} diff --git a/libs/generic-view/store/src/lib/views/actions.ts b/libs/generic-view/store/src/lib/views/actions.ts index fa0221358b..29683f1cf1 100644 --- a/libs/generic-view/store/src/lib/views/actions.ts +++ b/libs/generic-view/store/src/lib/views/actions.ts @@ -9,6 +9,7 @@ import { DeviceState } from "device-manager/models" import { DeviceBaseProperties } from "device-protocol/models" import { MenuElement } from "Core/__deprecated__/renderer/constants/menu-elements" import { ActionName } from "../action-names" +import { GenericForm } from "generic-view/models" export const addDevice = createAction< DeviceBaseProperties & Partial<{ state: DeviceState.Failed }> @@ -19,15 +20,6 @@ export const removeDevice = createAction( ) export const setMenu = createAction(ActionName.SetMenu) -export const setViewLayout = createAction<{ - feature: string - layout: View -}>(ActionName.SetViewLayout) - -export const setViewData = createAction<{ - feature: string - data: Record -}>(ActionName.SetViewData) export const setLastRefresh = createAction(ActionName.SetLastRefresh) @@ -35,6 +27,21 @@ export const setDeviceState = createAction<{ id: string; state: DeviceState }>( ActionName.SetDeviceState ) +export const registerForm = createAction<{ + formName: string + form: GenericForm + feature: string + deviceId: string +}>(ActionName.RegisterForm) + +export const setFormField = createAction<{ + formName: string + field: string + value: unknown + feature: string + deviceId: string +}>(ActionName.SetFormField) + export const setGenericConfig = createAction<{ config: View feature: string diff --git a/libs/generic-view/store/src/lib/views/reducer.ts b/libs/generic-view/store/src/lib/views/reducer.ts index 9f33dc3b0a..1ee96abf35 100644 --- a/libs/generic-view/store/src/lib/views/reducer.ts +++ b/libs/generic-view/store/src/lib/views/reducer.ts @@ -5,7 +5,6 @@ import { createReducer } from "@reduxjs/toolkit" import { MenuElement } from "Core/__deprecated__/renderer/constants/menu-elements" -import { View } from "generic-view/utils" import { DeviceState } from "device-manager/models" import { Device, Features } from "generic-view/models" import { ApiError } from "device/models" @@ -19,25 +18,18 @@ import { getOutboxData } from "../outbox/get-outbox-data.action" import { getGenericConfig } from "../features/get-generic-config.actions" import { addDevice, + registerForm, removeDevice, setDeviceState, + setFormField, setGenericConfig, setLastRefresh, setMenu, - setViewData, - setViewLayout, } from "./actions" import { transformGenericComponents } from "../features/transform-generic-components" export interface GenericState { menu: MenuElement[] | undefined - views: Record< - string, - { - layout: View - data: Record - } - > lastResponse: unknown lastRefresh?: number devices: Record @@ -46,7 +38,6 @@ export interface GenericState { const initialState: GenericState = { menu: undefined, - views: {}, lastResponse: {}, devices: {}, apiErrors: {}, @@ -56,18 +47,6 @@ export const genericViewsReducer = createReducer(initialState, (builder) => { builder.addCase(setMenu, (state, action) => { state.menu = action.payload }) - builder.addCase(setViewLayout, (state, action) => { - state.views[action.payload.feature] = { - ...state.views[action.payload.feature], - layout: action.payload.layout, - } - }) - builder.addCase(setViewData, (state, action) => { - state.views[action.payload.feature] = { - ...state.views[action.payload.feature], - data: action.payload.data, - } - }) builder.addCase(addDevice, (state, action) => { state.devices[action.payload.id] = { ...action.payload, @@ -197,6 +176,31 @@ export const genericViewsReducer = createReducer(initialState, (builder) => { } } }) + builder.addCase(registerForm, (state, action) => { + const { deviceId, feature, form, formName } = action.payload + state.devices[deviceId].features = { + ...state.devices[deviceId].features, + [feature]: { + ...state.devices[deviceId].features?.[feature], + forms: { + ...state.devices[deviceId].features?.[feature]?.forms, + [formName]: form, + }, + }, + } + }) + builder.addCase(setFormField, (state, action) => { + const { deviceId, feature, formName, field, value } = action.payload + const viewFeature = state.devices[deviceId].features?.[feature] + if ( + !viewFeature || + !viewFeature.forms || + !viewFeature.forms[formName] || + !field + ) + return + viewFeature.forms[formName].fields[field] = value + }) // Helper action for setting custom generic config without a need of reloading the app builder.addCase(setGenericConfig, (state, action) => { const { deviceId, feature, config } = action.payload diff --git a/libs/generic-view/ui/src/lib/interactive/form/form.tsx b/libs/generic-view/ui/src/lib/interactive/form/form.tsx index baad8e1483..264dcd39cf 100644 --- a/libs/generic-view/ui/src/lib/interactive/form/form.tsx +++ b/libs/generic-view/ui/src/lib/interactive/form/form.tsx @@ -12,6 +12,7 @@ import { CheckboxInput } from "./input/checkbox-input" import { SearchInput } from "./input/search-input" import { FormConfig } from "generic-view/models" import { FormConditionalRenderer } from "./helpers/form-conditional-renderer" +import { useFormRegister } from "generic-view/store" export const Form: APIFC & { TextInput: typeof TextInput @@ -25,6 +26,12 @@ export const Form: APIFC & { ...config?.formOptions, }) useViewFormRegister(componentKey!, methods) + useFormRegister({ + formName: componentKey!, + options: { + defaultValues: config?.defaultValues, + }, + }) return {children} } Form.TextInput = TextInput diff --git a/libs/generic-view/ui/src/lib/table/table.tsx b/libs/generic-view/ui/src/lib/table/table.tsx index 89d65ab0f4..f4cf7e5d7b 100644 --- a/libs/generic-view/ui/src/lib/table/table.tsx +++ b/libs/generic-view/ui/src/lib/table/table.tsx @@ -18,6 +18,7 @@ import { TableConfig, TableData } from "generic-view/models" import { TableCell } from "./table-cell" import { P1 } from "../texts/paragraphs" import { difference, intersection } from "lodash" +import { useFormField } from "generic-view/store" const rowHeight = 64 @@ -31,6 +32,9 @@ export const Table: APIFC & { -1, -1, ]) + const { setValue: setAllIds } = useFormField({ + formName: config.form.formName, + }) const { formOptions, columnsNames } = config const { activeIdFieldName } = formOptions @@ -49,6 +53,10 @@ export const Table: APIFC & { const handleScroll = useCallback(() => { if (!scrollWrapperRef.current) return const { scrollTop, clientHeight } = scrollWrapperRef.current + if (clientHeight === 0) { + setTimeout(handleScroll, 10) + return + } const rowsPerPage = Math.ceil(clientHeight / rowHeight) || 0 const currentRowIndex = Math.floor(scrollTop / rowHeight) const firstVisibleRowIndex = currentRowIndex - rowsPerPage @@ -59,8 +67,9 @@ export const Table: APIFC & { useEffect(() => { if (formOptions.allIdsFieldName) { formContext.setValue(formOptions.allIdsFieldName, data) + setAllIds(formOptions.allIdsFieldName, data) } - }, [data, formContext, formOptions.allIdsFieldName]) + }, [data, formContext, formOptions.allIdsFieldName, setAllIds]) useEffect(() => { if (formOptions.selectedIdsFieldName) { diff --git a/libs/generic-view/utils/src/index.ts b/libs/generic-view/utils/src/index.ts index 1cacf42916..bbc0d6a7c3 100644 --- a/libs/generic-view/utils/src/index.ts +++ b/libs/generic-view/utils/src/index.ts @@ -12,3 +12,4 @@ export * from "./lib/map-layout-sizes/map-layout-sizes" export * from "./lib/models/modal.types" export * from "./lib/data-provider-helpers" export * from "./lib/forms-provider/forms-provider" +export * from "./lib/use-current-view-key" diff --git a/libs/generic-view/utils/src/lib/use-current-view-key.ts b/libs/generic-view/utils/src/lib/use-current-view-key.ts new file mode 100644 index 0000000000..c8fc794045 --- /dev/null +++ b/libs/generic-view/utils/src/lib/use-current-view-key.ts @@ -0,0 +1,14 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { useParams } from "react-router" + +export const useCurrentViewKey = () => { + const { viewKey, subviewKey } = useParams<{ + viewKey: string + subviewKey?: string + }>() + return subviewKey || viewKey +}