diff --git a/apps/services/regulations-admin-backend/src/app/modules/draft_regulation/models/appendix.model.ts b/apps/services/regulations-admin-backend/src/app/modules/draft_regulation/models/appendix.model.ts index 4cace51397c8..12fbbd5f8dcc 100644 --- a/apps/services/regulations-admin-backend/src/app/modules/draft_regulation/models/appendix.model.ts +++ b/apps/services/regulations-admin-backend/src/app/modules/draft_regulation/models/appendix.model.ts @@ -1,4 +1,4 @@ -import { ApiProperty } from '@nestjs/swagger' +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger' import { HTMLText, PlainText } from '@island.is/regulations' export class AppendixModel { @@ -7,4 +7,7 @@ export class AppendixModel { @ApiProperty() text!: HTMLText + + @ApiPropertyOptional() + diff?: HTMLText } diff --git a/apps/services/regulations-admin-backend/src/main.ts b/apps/services/regulations-admin-backend/src/main.ts index b0f1f43fea55..9be0492bcc5c 100644 --- a/apps/services/regulations-admin-backend/src/main.ts +++ b/apps/services/regulations-admin-backend/src/main.ts @@ -7,5 +7,5 @@ bootstrap({ appModule: AppModule, name: 'regulations-admin-backend', openApi, - jsonBodyLimit: '300kb', + jsonBodyLimit: '400kb', }) diff --git a/libs/api/domains/regulations-admin/src/lib/graphql/dto/createDraftRegulationChange.input.ts b/libs/api/domains/regulations-admin/src/lib/graphql/dto/createDraftRegulationChange.input.ts index b4ab9905c0ab..64af25d4dddd 100644 --- a/libs/api/domains/regulations-admin/src/lib/graphql/dto/createDraftRegulationChange.input.ts +++ b/libs/api/domains/regulations-admin/src/lib/graphql/dto/createDraftRegulationChange.input.ts @@ -8,6 +8,9 @@ class CreateChangeAppendixInput { @Field(() => String, { nullable: true }) text!: HTMLText + + @Field(() => String, { nullable: true }) + diff?: HTMLText } @InputType() export class CreateDraftRegulationChangeInput { diff --git a/libs/api/domains/regulations-admin/src/lib/graphql/dto/updateDraftRegulationChange.input.ts b/libs/api/domains/regulations-admin/src/lib/graphql/dto/updateDraftRegulationChange.input.ts index c52fdccdcac5..7f017faa0845 100644 --- a/libs/api/domains/regulations-admin/src/lib/graphql/dto/updateDraftRegulationChange.input.ts +++ b/libs/api/domains/regulations-admin/src/lib/graphql/dto/updateDraftRegulationChange.input.ts @@ -8,6 +8,9 @@ class UpdateChangeAppendixInput { @Field(() => String, { nullable: true }) text!: HTMLText + + @Field(() => String, { nullable: true }) + diff?: HTMLText } @InputType() diff --git a/libs/api/domains/regulations-admin/src/lib/graphql/models/draftRegulationChange.model.ts b/libs/api/domains/regulations-admin/src/lib/graphql/models/draftRegulationChange.model.ts index 3d1f03e2163c..1f5e340f2b9c 100644 --- a/libs/api/domains/regulations-admin/src/lib/graphql/models/draftRegulationChange.model.ts +++ b/libs/api/domains/regulations-admin/src/lib/graphql/models/draftRegulationChange.model.ts @@ -8,6 +8,9 @@ export class ChangeAppendix { @Field(() => String, { nullable: true }) text!: HTMLText + + @Field(() => String, { nullable: true }) + diff?: HTMLText } @ObjectType() diff --git a/libs/portals/admin/regulations-admin/src/components/EditBasics.tsx b/libs/portals/admin/regulations-admin/src/components/EditBasics.tsx index 6cf202cbdd87..304a1e004f20 100644 --- a/libs/portals/admin/regulations-admin/src/components/EditBasics.tsx +++ b/libs/portals/admin/regulations-admin/src/components/EditBasics.tsx @@ -27,6 +27,8 @@ import { RegulationDraftTypes } from '../types' import ConfirmModal from './ConfirmModal/ConfirmModal' import { ReferenceText } from './impacts/ReferenceText' import { DraftChangeForm, DraftImpactForm } from '../state/types' +import { makeDraftAppendixForm } from '../state/makeFields' +import { hasAnyChange } from '../utils/formatAmendingUtils' const updateText = 'Ósamræmi er í texta stofnreglugerðar og breytingareglugerðar. Texti breytingareglugerðar þarf að samræmast breytingum sem gerðar hafa verið á stofnreglugerð, eigi breytingarnar að færast inn með réttum hætti.' @@ -37,6 +39,7 @@ export const EditBasics = () => { const [editorKey, setEditorKey] = useState('initial') const [titleError, setTitleError] = useState(undefined) const [hasUpdated, setHasUpdated] = useState(false) + const [hasUpdatedAppendix, setHasUpdatedAppendix] = useState(false) const [references, setReferences] = useState() const [isModalVisible, setIsModalVisible] = useState(true) const [hasConfirmed, setHasConfirmed] = useState(false) @@ -45,8 +48,7 @@ export const EditBasics = () => { const { text, appendixes } = draft const { updateState } = actions - const startTextExpanded = - !text.value || appendixes.length === 0 || !!text.error + const startTextExpanded = true const regType = draft.type.value && @@ -118,6 +120,45 @@ export const EditBasics = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [draft.impacts]) + useEffect(() => { + if (!hasUpdatedAppendix && hasUpdated) { + updateAppendixes() + setHasUpdatedAppendix(true) + } + }, [hasUpdated, hasUpdatedAppendix]) + + const updateAppendixes = () => { + // FORMAT AMENDING REGULATION APPENDIXES + const impactArray = Object.values(draft.impacts).flat() + const amendingArray = impactArray.filter( + (item) => item.type === 'amend', + ) as DraftChangeForm[] + + if (appendixes?.length > 0) { + appendixes.splice(0, appendixes.length) + } + + amendingArray.map((item) => { + item.appendixes.map((apx, idx) => { + if (apx.diff?.value && hasAnyChange(apx.diff.value)) { + const defaultTitle = apx.title.value ?? `Viðauki ${idx + 1}` + const defaultText = apx.text.value + if ( + appendixes?.length === 0 || + !appendixes.some((ap) => ap.text.value === defaultText) + ) { + appendixes.push( + makeDraftAppendixForm( + { title: defaultTitle, text: defaultText }, + String(appendixes.length), + ), + ) + } + } + }) + }) + } + const updateEditorText = () => { const additions = formatAmendingBodyWithArticlePrefix(draft.impacts) @@ -125,6 +166,7 @@ export const EditBasics = () => { updateState('title', formatAmendingRegTitle(draft)) const additionString = additions.join('') as HTMLText updateState('text', additionString) + setHasUpdated(true) } @@ -228,7 +270,7 @@ export const EditBasics = () => { name: (references[0].name as RegName) ?? '', appendixes: references[0].appendixes.map((apx) => ({ title: apx.title.value, - text: apx.text.value, + text: apx.diff?.value, })), } as Regulation } diff --git a/libs/portals/admin/regulations-admin/src/components/impacts/EditChange.tsx b/libs/portals/admin/regulations-admin/src/components/impacts/EditChange.tsx index 80e0109d7139..5610b4fbccc2 100644 --- a/libs/portals/admin/regulations-admin/src/components/impacts/EditChange.tsx +++ b/libs/portals/admin/regulations-admin/src/components/impacts/EditChange.tsx @@ -221,12 +221,32 @@ export const EditChange = (props: EditChangeProp) => { validateImpact(activeChange) }, [activeChange]) - const getDiffHtml = () => { - const emptyHTML = '' as HTMLText - const prev = previousRegulation?.text || emptyHTML - const current = activeChange.text.value || emptyHTML + const emptyHTML = '' as HTMLText + const getDiffHtml = (previous?: HTMLText, current?: HTMLText) => { + const prev = previous || previousRegulation?.text || emptyHTML + const curr = current || activeChange.text.value || emptyHTML - return getDiff(dirtyClean(prev), dirtyClean(current)).diff || emptyHTML + return getDiff(dirtyClean(prev), dirtyClean(curr)).diff || emptyHTML + } + + const getAppendixDiffHtml = (i: number) => { + const previous = previousRegulation?.appendixes[i]?.text || emptyHTML + const current = activeChange?.appendixes[i]?.text.value || emptyHTML + + const diff = getDiff(dirtyClean(previous), dirtyClean(current)).diff + + if (!previousRegulation?.appendixes[i]) { + // If the appendix is new + return `
${diff}
` as HTMLText + } + + if (diff) { + // If the appendix has changes + return diff + } else { + // If the appendix has no changes + return undefined + } } const saveChange = async () => { @@ -239,9 +259,10 @@ export const EditChange = (props: EditChangeProp) => { title: activeChange.title.value, text: activeChange.text.value, diff: getDiffHtml(), - appendixes: activeChange.appendixes.map((apx) => ({ + appendixes: activeChange.appendixes.map((apx, i) => ({ title: apx.title.value, text: apx.text.value, + diff: getAppendixDiffHtml(i), })), date: toISODate(activeChange.date.value), }, @@ -264,9 +285,10 @@ export const EditChange = (props: EditChangeProp) => { title: activeChange.title.value, text: activeChange.text.value, diff: getDiffHtml(), - appendixes: activeChange.appendixes.map((apx) => ({ + appendixes: activeChange.appendixes.map((apx, i) => ({ title: apx.title.value, text: apx.text.value, + diff: getAppendixDiffHtml(i), })), date: toISODate(activeChange.date.value), }, diff --git a/libs/portals/admin/regulations-admin/src/components/impacts/ReferenceText.tsx b/libs/portals/admin/regulations-admin/src/components/impacts/ReferenceText.tsx index 911dde865d50..15adaff457e9 100644 --- a/libs/portals/admin/regulations-admin/src/components/impacts/ReferenceText.tsx +++ b/libs/portals/admin/regulations-admin/src/components/impacts/ReferenceText.tsx @@ -87,7 +87,10 @@ export const ReferenceText = (props: ReferenceTextProps) => { {appendixes.map(({ title, text }, i) => (

{title}

- +
))} diff --git a/libs/portals/admin/regulations-admin/src/state/makeFields.ts b/libs/portals/admin/regulations-admin/src/state/makeFields.ts index 08893a853de9..c4c02a5a9b32 100644 --- a/libs/portals/admin/regulations-admin/src/state/makeFields.ts +++ b/libs/portals/admin/regulations-admin/src/state/makeFields.ts @@ -153,11 +153,12 @@ export const makeDraftChangeForm = ( // --------------------------------------------------------------------------- export const makeDraftAppendixForm = ( - appendix: Appendix, + appendix: Appendix & { diff?: HTMLText }, key: string, ): AppendixDraftForm => ({ title: fText(appendix.title, true), text: fHtml(appendix.text, true), + diff: appendix.diff ? fHtml(appendix.diff) : undefined, key, }) diff --git a/libs/portals/admin/regulations-admin/src/state/types.ts b/libs/portals/admin/regulations-admin/src/state/types.ts index 09256108c289..f04b7dc2cb26 100644 --- a/libs/portals/admin/regulations-admin/src/state/types.ts +++ b/libs/portals/admin/regulations-admin/src/state/types.ts @@ -47,6 +47,7 @@ export type AppendixDraftForm = { title: DraftField text: HtmlDraftField + diff?: HtmlDraftField /** * Appendixes may be revoked by `RegulationChange`s. * diff --git a/libs/portals/admin/regulations-admin/src/utils/formatAmendingRegulation.ts b/libs/portals/admin/regulations-admin/src/utils/formatAmendingRegulation.ts index 884527fd26c2..6c16e129d746 100644 --- a/libs/portals/admin/regulations-admin/src/utils/formatAmendingRegulation.ts +++ b/libs/portals/admin/regulations-admin/src/utils/formatAmendingRegulation.ts @@ -1,5 +1,9 @@ import { asDiv, HTMLText } from '@island.is/regulations' -import { GroupedDraftImpactForms, RegDraftForm } from '../state/types' +import { + AppendixDraftForm, + GroupedDraftImpactForms, + RegDraftForm, +} from '../state/types' import format from 'date-fns/format' import is from 'date-fns/locale/is' import compact from 'lodash/compact' @@ -10,8 +14,10 @@ import { extractArticleTitleDisplay, getTextWithSpaces, groupElementsByArticleTitleFromDiv, + hasAnyChange, isGildisTaka, removeRegPrefix, + updateAppendixWording, } from './formatAmendingUtils' import { getDeletionOrAddition } from './getDeletionOrAddition' @@ -173,6 +179,7 @@ export const formatAmendingRegBody = ( repeal?: boolean, diff?: HTMLText | string | undefined, regTitle?: string, + appendixes?: AppendixDraftForm[], ) => { const regName = removeRegNamePrefix(name) if (repeal) { @@ -409,6 +416,34 @@ export const formatAmendingRegBody = ( } }) + appendixes?.map((apx, idx) => { + if (apx.diff?.value) { + const defaultTitle = apx.title.value ?? `Viðauki ${idx + 1}` + + const regNameAddition = + regName && regName !== 'self' + ? `reglugerð nr. ${regName}`.replace(/\.$/, '') + : 'reglugerðina' + const regNameChange = + regName && regName !== 'self' + ? `, reglugerðar nr. ${regName}`.replace(/\.$/, '') + : '' + + const testAddTitle = `Við ${regNameAddition} bætist nýr viðauki, ${defaultTitle} sem ${ + /fylgiskjal/i.test(defaultTitle) ? 'birt' : 'birtur' + } er með reglugerð þessari.` + const testChangeTitle = `Eftirfarandi breytingar eru gerðar á ${updateAppendixWording( + defaultTitle, + )}${regNameChange}:` + + if (apx.diff?.value.includes('
')) { + additionArray.push([`

${testAddTitle}

` as HTMLText]) + } else if (hasAnyChange(apx.diff?.value)) { + additionArray.push([`

${testChangeTitle}

[]

` as HTMLText]) + } + } + }) + return additionArray.flat() } @@ -426,6 +461,7 @@ export const formatAmendingBodyWithArticlePrefix = ( item.type === 'repeal', item.type === 'amend' ? item.diff?.value : undefined, item.regTitle, + item.type === 'amend' ? item.appendixes : undefined, ), date: item.date.value, } diff --git a/libs/portals/admin/regulations-admin/src/utils/formatAmendingUtils.ts b/libs/portals/admin/regulations-admin/src/utils/formatAmendingUtils.ts index 007246a3332a..3c788317fec8 100644 --- a/libs/portals/admin/regulations-admin/src/utils/formatAmendingUtils.ts +++ b/libs/portals/admin/regulations-admin/src/utils/formatAmendingUtils.ts @@ -1,5 +1,5 @@ import isSameDay from 'date-fns/isSameDay' -import { HTMLText } from '@island.is/regulations' +import { HTMLText, asDiv } from '@island.is/regulations' export const groupElementsByArticleTitleFromDiv = ( div: HTMLDivElement, @@ -87,3 +87,30 @@ export const allSameDay = (objects: AdditionObject[]): boolean => { return validObjects.every((obj) => isSameDay(obj.date!, firstDate)) } + +export const hasAnyChange = (diff: string) => { + const testElement = asDiv(diff) + const hasDeletion = !!testElement.querySelector('del') + const hasInsert = !!testElement.querySelector('ins') + + return hasDeletion || hasInsert +} + +export const updateAppendixWording = (input: string): string => { + return input.replace(/fylgiskjal|viðauki/gi, (match) => { + if (match[0] === match[0].toUpperCase()) { + if (match.toLowerCase() === 'fylgiskjal') { + return 'Fylgiskjali' + } else if (match.toLowerCase() === 'viðauki') { + return 'Viðauka' + } + } else { + if (match.toLowerCase() === 'fylgiskjal') { + return 'fylgiskjali' + } else if (match.toLowerCase() === 'viðauki') { + return 'viðauka' + } + } + return match + }) +}