Skip to content

Commit

Permalink
Let redaktør select not yet used sections for template
Browse files Browse the repository at this point in the history
  • Loading branch information
eriksson-daniel committed Nov 25, 2024
1 parent c8249fd commit 6aa17db
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 106 deletions.
3 changes: 1 addition & 2 deletions frontend/src/components/maltekstseksjoner/filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
useUpdateUtfallIdListMutation,
useUpdateYtelseHjemmelIdListMutation,
} from '@app/redux-api/maltekstseksjoner/mutations';
import { type IGetMaltekstseksjonParams, MALTEKSTSEKSJON_TYPE } from '@app/types/common-text-types';
import type { IGetMaltekstseksjonParams } from '@app/types/common-text-types';
import type { IMaltekstseksjon } from '@app/types/maltekstseksjoner/responses';
import { styled } from 'styled-components';

Expand All @@ -29,7 +29,6 @@ export const Filters = ({ maltekst, query }: Props) => {
return (
<Container>
<TemplateSectionSelect
textType={MALTEKSTSEKSJON_TYPE}
selected={maltekst.templateSectionIdList}
onChange={(templateSectionIdList) => updateTemplateSection({ id: maltekst.id, templateSectionIdList, query })}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { HjemlerSelect } from '@app/components/smart-editor-texts/hjemler-select
import { useUtfallOptions } from '@app/components/smart-editor-texts/hooks/use-options';
import { useTextQuery } from '@app/components/smart-editor-texts/hooks/use-text-query';
import { TemplateSectionSelect, UtfallSelect } from '@app/components/smart-editor-texts/query-filter-selects';
import { type IGetMaltekstseksjonParams, MALTEKSTSEKSJON_TYPE } from '@app/types/common-text-types';
import type { IGetMaltekstseksjonParams } from '@app/types/common-text-types';
import { useSearchParams } from 'react-router-dom';
import { styled } from 'styled-components';

Expand All @@ -28,7 +28,6 @@ export const Filters = () => {
<TemplateSectionSelect
selected={templateSectionIdList ?? []}
onChange={(value) => setFilter('templateSectionIdList', value)}
textType={MALTEKSTSEKSJON_TYPE}
includeNoneOption
templatesSelectable
>
Expand Down
7 changes: 3 additions & 4 deletions frontend/src/components/smart-editor-texts/edit/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const Edit = ({ text, onDraftDeleted, children, status, onPublish, delete

const { id, created, ytelseHjemmelIdList, utfallIdList, enhetIdList, templateSectionIdList, title, textType } = text;

const { enhet, templateSection, utfall, ytelseHjemmel } = useMetadataFilters(textType);
const { enhet, utfall, ytelseHjemmel } = useMetadataFilters(textType);

const [lastEdit] = text.edits;

Expand All @@ -67,12 +67,11 @@ export const Edit = ({ text, onDraftDeleted, children, status, onPublish, delete
</LineContainer>

<LineContainer>
{templateSection ? (
{textType === GOD_FORMULERING_TYPE ? (
<TemplateSectionSelect
selected={templateSectionIdList}
onChange={(v) => updateTemplateSectionIdList({ id, query, templateSectionIdList: v })}
textType={textType}
templatesSelectable={textType === GOD_FORMULERING_TYPE}
templatesSelectable
>
Maler og seksjoner
</TemplateSectionSelect>
Expand Down
7 changes: 3 additions & 4 deletions frontend/src/components/smart-editor-texts/filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
TemplateSectionSelect,
UtfallSelect,
} from '@app/components/smart-editor-texts/query-filter-selects';
import type { IGetMaltekstseksjonParams, TextTypes } from '@app/types/common-text-types';
import { GOD_FORMULERING_TYPE, type IGetMaltekstseksjonParams, type TextTypes } from '@app/types/common-text-types';
import { useSearchParams } from 'react-router-dom';
import { styled } from 'styled-components';
import { HjemlerSelect } from './hjemler-select/hjemler-select';
Expand All @@ -18,7 +18,7 @@ interface Props {

export const Filters = ({ textType, className }: Props) => {
const [searchParams, setSearchParams] = useSearchParams();
const { enhet, templateSection, utfall, ytelseHjemmel } = useMetadataFilters(textType);
const { enhet, utfall, ytelseHjemmel } = useMetadataFilters(textType);

const { enhetIdList, utfallIdList, templateSectionIdList, ytelseHjemmelIdList } = useTextQuery();

Expand All @@ -36,11 +36,10 @@ export const Filters = ({ textType, className }: Props) => {

return (
<Container className={className}>
{templateSection ? (
{textType === GOD_FORMULERING_TYPE ? (
<TemplateSectionSelect
selected={templateSectionIdList ?? []}
onChange={(value) => setFilter('templateSectionIdList', value)}
textType={textType}
includeNoneOption
templatesSelectable
>
Expand Down
73 changes: 26 additions & 47 deletions frontend/src/components/smart-editor-texts/get-template-options.tsx
Original file line number Diff line number Diff line change
@@ -1,65 +1,44 @@
import { type NestedOption, OptionType } from '@app/components/filter-dropdown/nested-filter-list';
import { GLOBAL, LIST_DELIMITER, NONE_OPTION, WILDCARD } from '@app/components/smart-editor-texts/types';
import { MALTEKST_SECTION_NAMES } from '@app/components/smart-editor/constants';
import { type SectionType, getTemplateSections } from '@app/hooks/use-template-sections';
import {
ELEMENT_MALTEKST,
ELEMENT_MALTEKSTSEKSJON,
ELEMENT_REDIGERBAR_MALTEKST,
} from '@app/plate/plugins/element-types';
import { getTemplateSections } from '@app/hooks/use-template-sections';
import { TemplateSections } from '@app/plate/template-sections';
import { TEMPLATES } from '@app/plate/templates/templates';
import {
GOD_FORMULERING_TYPE,
MALTEKSTSEKSJON_TYPE,
RichTextTypes,
type TextTypes,
} from '@app/types/common-text-types';

export const ALL_TEMPLATES_LABEL = 'Alle maler';

const getSectionType = (textType: TextTypes): SectionType | undefined => {
switch (textType) {
case MALTEKSTSEKSJON_TYPE:
return ELEMENT_MALTEKSTSEKSJON;
case RichTextTypes.MALTEKST:
return ELEMENT_MALTEKST;
case RichTextTypes.REDIGERBAR_MALTEKST:
return ELEMENT_REDIGERBAR_MALTEKST;
default:
return undefined;
}
};

export const getTemplateOptions = (
textType: TextTypes,
includeNone: boolean,
templatesSelectable: boolean,
): NestedOption[] => {
const isMaltekst = textType !== GOD_FORMULERING_TYPE;
export const getTemplateOptions = (includeNone: boolean, templatesSelectable: boolean): NestedOption[] => {
const options: NestedOption[] = TEMPLATES.map(({ templateId, tittel }) => {
const { used, unused } = getTemplateSections(templateId);

const options: NestedOption[] = [];

for (const { templateId, tittel } of TEMPLATES) {
const sections = getTemplateSections(templateId, getSectionType(textType));
const unusedOption = {
type: OptionType.GROUP,
value: 'UNUSED',
label: 'Ubrukte seksjoner',
filterValue: 'Ubrukte seksjoner',
options: unused.map((s) => ({
type: OptionType.OPTION,
value: `${templateId}${LIST_DELIMITER}${s}`,
label: MALTEKST_SECTION_NAMES[s],
filterValue: `${tittel} ${MALTEKST_SECTION_NAMES[s]}`,
})),
};

if (isMaltekst && sections.length === 0) {
continue;
}
const usedOptions = used.map((s) => ({
type: OptionType.OPTION,
value: `${templateId}${LIST_DELIMITER}${s}`,
label: MALTEKST_SECTION_NAMES[s],
filterValue: `${tittel} ${MALTEKST_SECTION_NAMES[s]}`,
}));

options.push({
return {
type: templatesSelectable ? OptionType.OPTION : OptionType.GROUP,
label: tittel,
value: `${templateId}${LIST_DELIMITER}${WILDCARD}`,
filterValue: templateId,
options: sections.map((s) => ({
type: OptionType.OPTION,
value: `${templateId}${LIST_DELIMITER}${s}`,
label: MALTEKST_SECTION_NAMES[s],
filterValue: `${tittel} ${MALTEKST_SECTION_NAMES[s]}`,
})),
});
}
options: usedOptions.concat(unusedOption),
};
});

options.push({
type: templatesSelectable ? OptionType.OPTION : OptionType.GROUP,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { NONE, NONE_OPTION, type NONE_TYPE, SET_DELIMITER } from '@app/component
import { ToggleButton } from '@app/components/toggle-button/toggle-button';
import { isUtfall } from '@app/functions/is-utfall';
import { useOnClickOutside } from '@app/hooks/use-on-click-outside';
import type { TextTypes } from '@app/types/common-text-types';
import type { UtfallEnum } from '@app/types/kodeverk';
import { useCallback, useMemo, useRef, useState } from 'react';
import { styled } from 'styled-components';
Expand Down Expand Up @@ -106,7 +105,6 @@ interface TemplateSelectProps {
children: string;
selected: string[];
onChange: (value: string[]) => void;
textType: TextTypes;
includeNoneOption?: boolean;
templatesSelectable?: boolean;
}
Expand All @@ -115,13 +113,12 @@ export const TemplateSectionSelect = ({
selected,
children,
onChange,
textType,
includeNoneOption = false,
templatesSelectable = false,
}: TemplateSelectProps) => {
const templates = useMemo(
() => getTemplateOptions(textType, includeNoneOption, templatesSelectable),
[includeNoneOption, templatesSelectable, textType],
() => getTemplateOptions(includeNoneOption, templatesSelectable),
[includeNoneOption, templatesSelectable],
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ export const SectionSelect = ({ activeSection, setActiveSection }: Props) => {
const { templateId } = useContext(SmartEditorContext);
const editor = useMyPlateEditorRef();
const selection = useSelection();
const sections = useTemplateSections(templateId);

const { used } = useTemplateSections(templateId);

useEffect(() => {
if (selection === null) {
Expand All @@ -75,13 +76,13 @@ export const SectionSelect = ({ activeSection, setActiveSection }: Props) => {
<option key={NONE} value={NONE}>
Alle gode formuleringer
</option>,
...sections.map((section) => (
...used.map((section) => (
<option key={section} value={section}>
{MALTEKST_SECTION_NAMES[section]}
</option>
)),
],
[sections],
[used],
);

const value = activeSection === NONE ? NONE : activeSection;
Expand Down
64 changes: 25 additions & 39 deletions frontend/src/hooks/use-template-sections.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,47 @@
import type {
ELEMENT_FOOTER,
ELEMENT_HEADER,
ELEMENT_MALTEKST,
ELEMENT_MALTEKSTSEKSJON,
ELEMENT_REDIGERBAR_MALTEKST,
} from '@app/plate/plugins/element-types';
import { ELEMENT_MALTEKSTSEKSJON } from '@app/plate/plugins/element-types';
import { TemplateSections } from '@app/plate/template-sections';
import { TEMPLATE_MAP } from '@app/plate/templates/templates';
import type { MaltekstseksjonElement } from '@app/plate/types';
import { isOfElementType } from '@app/plate/utils/queries';
import type { TemplateIdEnum } from '@app/types/smart-editor/template-enums';
import { type TDescendant, type Value, isElement } from '@udecode/plate-common';
import type { TDescendant, Value } from '@udecode/plate-common';
import { useMemo } from 'react';

const EMPTY_LIST: TemplateSections[] = [];

export type SectionType =
| typeof ELEMENT_MALTEKSTSEKSJON
| typeof ELEMENT_MALTEKST
| typeof ELEMENT_REDIGERBAR_MALTEKST
| typeof ELEMENT_FOOTER
| typeof ELEMENT_HEADER;
interface GroupedTemplateSections {
used: TemplateSections[];
unused: TemplateSections[];
}

export const useTemplateSections = (templateId: TemplateIdEnum, sectionType?: SectionType): TemplateSections[] =>
useMemo(() => getTemplateSections(templateId, sectionType), [templateId, sectionType]);
export const useTemplateSections = (templateId: TemplateIdEnum): GroupedTemplateSections =>
useMemo(() => getTemplateSections(templateId), [templateId]);

export const getTemplateSections = (templateId: TemplateIdEnum, sectionType?: SectionType): TemplateSections[] => {
export const getTemplateSections = (templateId: TemplateIdEnum): GroupedTemplateSections => {
const template = TEMPLATE_MAP[templateId];

if (template === undefined) {
return EMPTY_LIST;
return { used: EMPTY_LIST, unused: TEMPLATE_SECTIONS };
}

return getSections(template.richText as Value, sectionType);
return getSections(template.richText as Value);
};

const getSections = (children: TDescendant[], sectionType?: SectionType): TemplateSections[] => {
const sectionSet = new Set<TemplateSections>();

for (const element of children) {
if (isElement(element)) {
if ('section' in element && isTemplateSection(element.section)) {
const sectionTypeMatches = sectionType === undefined || element.type === sectionType;

if (sectionTypeMatches) {
sectionSet.add(element.section);
}
}

for (const s of getSections(element.children, sectionType)) {
sectionSet.add(s);
}
const getSections = (children: TDescendant[]): GroupedTemplateSections => {
const used: TemplateSections[] = [];
const unused: TemplateSections[] = [];

for (const section of TEMPLATE_SECTIONS) {
if (
children.some((c) => isOfElementType<MaltekstseksjonElement>(c, ELEMENT_MALTEKSTSEKSJON) && c.section === section)
) {
used.push(section);
} else {
unused.push(section);
}
}

return Array.from(sectionSet);
return { used, unused };
};

const TEMPLATE_SECTIONS = Object.values(TemplateSections);

const isTemplateSection = (section: unknown): section is TemplateSections =>
typeof section === 'string' && TEMPLATE_SECTIONS.some((s) => s === section);

0 comments on commit 6aa17db

Please sign in to comment.