Skip to content

Commit

Permalink
Merge branch 'main' into feature/table-radio-button
Browse files Browse the repository at this point in the history
  • Loading branch information
adamhaeger committed Nov 20, 2024
2 parents 752494d + d8edfe8 commit 898fe83
Show file tree
Hide file tree
Showing 25 changed files with 322 additions and 404 deletions.
5 changes: 1 addition & 4 deletions src/components/form/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,7 @@ export function FormPage({ currentPageId }: { currentPageId: string | undefined
return (
<>
<ErrorProcessing setFormState={setFormState} />
<Loader
reason='form-ids'
renderPresentation={false}
/>
<Loader reason='form-ids' />
</>
);
}
Expand Down
74 changes: 42 additions & 32 deletions src/components/presentation/Presentation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Header } from 'src/components/presentation/Header';
import { NavBar } from 'src/components/presentation/NavBar';
import classes from 'src/components/presentation/Presentation.module.css';
import { Progress } from 'src/components/presentation/Progress';
import { createContext } from 'src/core/contexts/context';
import { RenderStart } from 'src/core/ui/RenderStart';
import { Footer } from 'src/features/footer/Footer';
import { useUiConfigContext } from 'src/features/form/layout/UiConfigContext';
Expand Down Expand Up @@ -45,38 +46,40 @@ export const PresentationComponent = ({ header, type, children, renderNavBar = t

return (
<RenderStart>
<div
data-testid='presentation'
data-expanded={JSON.stringify(expandedWidth)}
className={cn(classes.container, { [classes.expanded]: expandedWidth })}
>
<AltinnAppHeader
party={party}
userParty={userParty}
logoColor={LogoColor.blueDarker}
headerBackgroundColor={backgroundColor}
/>
<main className={classes.page}>
{isProcessStepsArchived && instanceStatus?.substatus && (
<AltinnSubstatusPaper
label={<Lang id={instanceStatus.substatus.label} />}
description={<Lang id={instanceStatus.substatus.description} />}
/>
)}
{renderNavBar && <NavBar type={type} />}
<section
id='main-content'
className={classes.modal}
tabIndex={-1}
>
<Header header={realHeader}>
<ProgressBar type={type} />
</Header>
<div className={classes.modalBody}>{children}</div>
</section>
</main>
<Footer />
</div>
<PresentationProvider value={undefined}>
<div
data-testid='presentation'
data-expanded={JSON.stringify(expandedWidth)}
className={cn(classes.container, { [classes.expanded]: expandedWidth })}
>
<AltinnAppHeader
party={party}
userParty={userParty}
logoColor={LogoColor.blueDarker}
headerBackgroundColor={backgroundColor}
/>
<main className={classes.page}>
{isProcessStepsArchived && instanceStatus?.substatus && (
<AltinnSubstatusPaper
label={<Lang id={instanceStatus.substatus.label} />}
description={<Lang id={instanceStatus.substatus.description} />}
/>
)}
{renderNavBar && <NavBar type={type} />}
<section
id='main-content'
className={classes.modal}
tabIndex={-1}
>
<Header header={realHeader}>
<ProgressBar type={type} />
</Header>
<div className={classes.modalBody}>{children}</div>
</section>
</main>
<Footer />
</div>
</PresentationProvider>
</RenderStart>
);
};
Expand All @@ -98,3 +101,10 @@ function ProgressBar({ type }: { type: ProcessTaskType | PresentationType }) {
</Grid>
);
}

const { Provider: PresentationProvider, useHasProvider } = createContext<undefined>({
name: 'Presentation',
required: true,
});

export const useHasPresentation = () => useHasProvider();
8 changes: 2 additions & 6 deletions src/components/wrappers/ProcessWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Route, Routes } from 'react-router-dom';
import Grid from '@material-ui/core/Grid';

import { Button } from 'src/app-components/button/Button';
import { Form, FormFirstPage } from 'src/components/form/Form';
import { Form } from 'src/components/form/Form';
import { PresentationComponent } from 'src/components/presentation/Presentation';
import classes from 'src/components/wrappers/ProcessWrapper.module.css';
import { Loader } from 'src/core/loading/Loader';
Expand Down Expand Up @@ -187,7 +187,7 @@ export const ProcessWrapper = () => {
}
/>
<Route
path=':pageKey'
path='*'
element={
<PDFWrapper>
<PresentationComponent type={realTaskType}>
Expand All @@ -196,10 +196,6 @@ export const ProcessWrapper = () => {
</PDFWrapper>
}
/>
<Route
path='*'
element={<FormFirstPage />}
/>
</Routes>
</FormProvider>
);
Expand Down
8 changes: 4 additions & 4 deletions src/core/contexts/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ export function createContext<T>({ name, required, ...rest }: CreateContextProps
});
Context.displayName = name;

const useHasProvider = () => Boolean(useContext(Context).provided);
const useHasProvider = () => useContext(Context).provided;

const useCtx = (): T => {
const hasProvider = useHasProvider();
const value = useContext(Context).innerValue;
if (!hasProvider) {
const ctx = useContext(Context);
const value = ctx.innerValue;
if (!ctx.provided) {
if (required) {
throw new Error(`${name} is missing`);
}
Expand Down
16 changes: 8 additions & 8 deletions src/core/loading/Loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';

import { AltinnContentIconFormData } from 'src/components/atoms/AltinnContentIconFormData';
import { AltinnContentLoader } from 'src/components/molecules/AltinnContentLoader';
import { PresentationComponent } from 'src/components/presentation/Presentation';
import { PresentationComponent, useHasPresentation } from 'src/components/presentation/Presentation';
import { useTaskStore } from 'src/core/contexts/taskStoreContext';
import { LoadingProvider } from 'src/core/loading/LoadingContext';
import { Lang } from 'src/features/language/Lang';
Expand All @@ -11,12 +11,12 @@ import { ProcessTaskType } from 'src/types';
interface LoaderProps {
reason: string; // The reason is used by developers to identify the reason for the loader
details?: string;
renderPresentation?: boolean;
}

export const Loader = ({ renderPresentation = true, ...rest }: LoaderProps) => {
export const Loader = (props: LoaderProps) => {
const overriddenDataModelUuid = useTaskStore((state) => state.overriddenDataModelUuid);
const overriddenTaskId = useTaskStore((state) => state.overriddenTaskId);
const hasPresentation = useHasPresentation();

if (overriddenDataModelUuid) {
return null;
Expand All @@ -25,23 +25,23 @@ export const Loader = ({ renderPresentation = true, ...rest }: LoaderProps) => {
if (overriddenTaskId) {
return null;
}
if (renderPresentation) {
if (!hasPresentation) {
return (
<LoadingProvider reason={rest.reason}>
<LoadingProvider reason={props.reason}>
<PresentationComponent
header={<Lang id='instantiate.starting' />}
type={ProcessTaskType.Unknown}
renderNavBar={false}
>
<InnerLoader {...rest} />
<InnerLoader {...props} />
</PresentationComponent>
</LoadingProvider>
);
}

return (
<LoadingProvider reason={rest.reason}>
<InnerLoader {...rest} />
<LoadingProvider reason={props.reason}>
<InnerLoader {...props} />
</LoadingProvider>
);
};
Expand Down
7 changes: 0 additions & 7 deletions src/features/formData/FormDataWrite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -971,11 +971,4 @@ export const FD = {

return useCallback((dataElementId: string) => map[dataElementId], [map]);
},

/**
* This lets you set to a function that will be called as soon as the saving operation finishes.
* Beware that this is not a subscription service, so you can easily overwrite an existing callback here. This
* is only meant to be used in NodesContext.
*/
useSetOnSaveFinished: () => useSelector((s) => s.setOnSaveFinished),
};
11 changes: 0 additions & 11 deletions src/features/formData/FormDataWriteStateMachine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,6 @@ type FormDataState = {
// This contains the validation issues we receive from the server last time we saved the data model.
validationIssues: BackendValidationIssueGroups | undefined;

// This may contain a callback function that will be called whenever the save finishes.
// Should only be set from NodesContext.
onSaveFinished: ((result: FDSaveFinished) => void) | undefined;
setOnSaveFinished: (callback: (result: FDSaveFinished) => void) => void;

// This is used to track which component is currently blocking the auto-saving feature. If this is set to a string
// value, auto-saving will be disabled, even if the autoSaving flag is set to true. This is useful when you want
// to temporarily disable auto-saving, for example when clicking a CustomButton and waiting for the server to
Expand Down Expand Up @@ -238,7 +233,6 @@ function makeActions(
const { validationIssues, savedData, newDataModels, instance } = toProcess;
state.manualSaveRequested = false;
state.validationIssues = validationIssues;
state.onSaveFinished?.(toProcess);

if (instance && changeInstance) {
changeInstance(() => instance);
Expand Down Expand Up @@ -548,11 +542,6 @@ export const createFormDataWriteStore = (
debounceTimeout: DEFAULT_DEBOUNCE_TIMEOUT,
manualSaveRequested: false,
validationIssues: undefined,
onSaveFinished: undefined,
setOnSaveFinished: (callback) =>
set((state) => {
state.onSaveFinished = callback;
}),
...actions,
};
}),
Expand Down
30 changes: 23 additions & 7 deletions src/features/routing/AppRoutingContext.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useEffect } from 'react';
import { matchPath, useLocation, useNavigate as useNativeNavigate } from 'react-router-dom';
import type { MutableRefObject, PropsWithChildren } from 'react';
import type { NavigateOptions } from 'react-router-dom';

import { createStore } from 'zustand';

Expand Down Expand Up @@ -30,17 +31,18 @@ interface Context {
updateHash: (hash: string) => void;
effectCallback: NavigationEffectCb | null;
setEffectCallback: (cb: NavigationEffectCb | null) => void;
navigateRef: MutableRefObject<ReturnType<typeof useNativeNavigate>>;
navigateRef: MutableRefObject<SimpleNavigate | undefined>;
}

export type SimpleNavigate = (target: string, options?: NavigateOptions) => void;

function newStore({ initialLocation }: { initialLocation: string | undefined }) {
return createStore<Context>((set) => ({
hash: initialLocation ? initialLocation : `${window.location.hash}`,
updateHash: (hash: string) => set({ hash }),
effectCallback: null,
setEffectCallback: (effectCallback: NavigationEffectCb) => set({ effectCallback }),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
navigateRef: { current: undefined as any },
navigateRef: { current: undefined },
}));
}

Expand Down Expand Up @@ -139,11 +141,13 @@ export const useIsSubformPage = () =>
useSelector((s) => {
const path = getPath(s.hash);
const matches = matchers.map((matcher) => matchPath(matcher, path));
return !!paramFrom(matches, 'mainPageKey');
const mainPageKey = paramFrom(matches, 'mainPageKey');
const subformPageKey = paramFrom(matches, 'pageKey');
return !!(mainPageKey && subformPageKey);
});

// Use this instead of the native one to avoid re-rendering whenever the route changes
export const useNavigate = () => useSelector((ctx) => ctx.navigateRef).current;
export const useNavigate = () => useStaticSelector((ctx) => ctx.navigateRef).current!;

const matchers: string[] = [
'/instance/:partyId/:instanceGuid',
Expand Down Expand Up @@ -198,8 +202,20 @@ function UpdateHash() {
}

function UpdateNavigate() {
const navigateRef = useSelector((ctx) => ctx.navigateRef);
navigateRef.current = useNativeNavigate();
const store = useStore();
const navigateRef = useStaticSelector((ctx) => ctx.navigateRef);
const nativeNavigate = useNativeNavigate();

navigateRef.current = (target, options) => {
if (target && !target.startsWith('/')) {
// Used for relative navigation, e.g. navigating to a subform page
const currentPath = getPath(store.getState().hash).replace(/\/$/, '');
const newTarget = `${currentPath}/${target}`;
nativeNavigate(newTarget, options);
return;
}
nativeNavigate(target, options);
};

return null;
}
19 changes: 7 additions & 12 deletions src/features/validation/StoreValidationsInNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { GeneratorCondition, StageFormValidation } from 'src/utils/layout/genera
import { NodesInternal } from 'src/utils/layout/NodesContext';
import type { AnyValidation, AttachmentValidation } from 'src/features/validation/index';
import type { CompCategory } from 'src/layout/common';
import type { TypesFromCategory } from 'src/layout/layout';
import type { CompIntermediate, TypesFromCategory } from 'src/layout/layout';
import type { LayoutNode } from 'src/utils/layout/LayoutNode';

export function StoreValidationsInNode() {
Expand All @@ -29,9 +29,9 @@ type Node = LayoutNode<TypesFromCategory<CompCategory.Form | CompCategory.Contai
function StoreValidationsInNodeWorker() {
const item = GeneratorInternal.useIntermediateItem()!;
const node = GeneratorInternal.useParent() as Node;
const shouldValidate = !('renderAsSummary' in item && item.renderAsSummary);
const shouldValidate = shouldValidateNode(item);

const { validations: freshValidations, processedLast } = useNodeValidation(node, shouldValidate);
const freshValidations = useNodeValidation(node, shouldValidate);
const validations = useUpdatedValidations(freshValidations, node);

const shouldSetValidations = NodesInternal.useNodeData(node, (data) => !deepEqual(data.validations, validations));
Expand All @@ -56,15 +56,6 @@ function StoreValidationsInNodeWorker() {
visibilityToSet !== undefined,
);

const shouldSetProcessedLast = NodesInternal.useNodeData(
node,
(data) => data.validationsProcessedLast !== processedLast,
);
NodesStateQueue.useSetNodeProp(
{ node, prop: 'validationsProcessedLast', value: processedLast, force: true },
shouldSetProcessedLast,
);

return null;
}

Expand All @@ -91,3 +82,7 @@ function useUpdatedValidations(validations: AnyValidation[], node: Node) {
return copy;
});
}

export function shouldValidateNode(item: CompIntermediate): boolean {
return !('renderAsSummary' in item && item.renderAsSummary);
}
Loading

0 comments on commit 898fe83

Please sign in to comment.