From 87a976d44b9c5064ebe13caa5eab9feea4c4c471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9E=C3=B3r=C3=B0ur=20H?= Date: Mon, 9 Sep 2024 03:25:39 +0000 Subject: [PATCH] feat(regulations-admin): Add affected regulation formatting (#15857) * Add affected regulation formatting * Order articles by affected article number --- .../src/utils/formatAmendingRegulation.ts | 169 ++++++++++++++---- 1 file changed, 135 insertions(+), 34 deletions(-) diff --git a/libs/portals/admin/regulations-admin/src/utils/formatAmendingRegulation.ts b/libs/portals/admin/regulations-admin/src/utils/formatAmendingRegulation.ts index d4cccd26ac03..ac3fca2aef41 100644 --- a/libs/portals/admin/regulations-admin/src/utils/formatAmendingRegulation.ts +++ b/libs/portals/admin/regulations-admin/src/utils/formatAmendingRegulation.ts @@ -1,6 +1,10 @@ import { asDiv, HTMLText } from '@island.is/regulations' import { GroupedDraftImpactForms, RegDraftForm } from '../state/types' +import format from 'date-fns/format' +import is from 'date-fns/locale/is' +import compact from 'lodash/compact' import flatten from 'lodash/flatten' +import uniq from 'lodash/uniq' import { groupElementsByArticleTitleFromDiv } from './groupByArticleTitle' import { getDeletionOrAddition } from './getDeletionOrAddition' @@ -16,17 +20,107 @@ const removeRegPrefix = (title: string) => { return title } -const moveMatchingStringsToEnd = (arr: Array) => { - const isGildisTaka = (str: string) => { - return /(öðlast|tekur).*gildi|sett.*með.*(?:heimild|stoð)/.test( - (str || '').toLowerCase(), - ) +const isGildisTaka = (str: string) => { + return /(öðlast|tekur).*gildi|sett.*með.*(?:heimild|stoð)/.test( + (str || '').toLowerCase(), + ) +} + +const formatAffectedAndPlaceAffectedAtEnd = ( + groups: { + formattedRegBody: HTMLText[] + date?: Date | undefined + }[], +) => { + function formatArray(arr: string[]): string { + if (arr.length === 1) { + return arr[0] + } else if (arr.length === 2) { + return arr.join(' og ') + } else if (arr.length > 2) { + const lastItem = arr.pop() + const joinedItems = arr.join(', ') + const cleanString = `${joinedItems} og ${lastItem}`.replace( + / +(?= )/g, + '', + ) + + return cleanString + } + + return '' } - const matchingStrings = arr.filter((str) => isGildisTaka(str)) - const nonMatchingStrings = arr.filter((str) => !isGildisTaka(str)) + const formatDate = (date: Date) => { + const newDate = new Date(date) + if (newDate) { + const formattedDate = format(new Date(date), 'dd. MMMM yyyy', { + locale: is, + }) + return formattedDate.replace(/^0+/, '') // Remove leading zeros + } else { + return '' + } + } + + const extractArticleNumber = (str: string): number | null => { + const match = str.match(/(\d+)\. gr/) + return match ? parseInt(match[1], 10) : null + } + + let articleNumber = 0 + const gildsTakaKeepArray: HTMLText[] = [] + const articleKeepArray: { text: HTMLText; originalIndex: number }[] = [] + const impactAffectArray: HTMLText[] = [] + + groups.forEach((item) => { + const affectedImpacts: HTMLText[] = [] + item.formattedRegBody.forEach((body) => { + if (isGildisTaka(body)) { + gildsTakaKeepArray.push(body) + } else { + articleKeepArray.push({ text: body, originalIndex: articleNumber }) + affectedImpacts.push(`${articleNumber + 1}. gr.` as HTMLText) + articleNumber++ + } + }) + const impactString = formatArray(affectedImpacts) + const impactAffectedString = `Ákvæði ${impactString} reglugerðarinnar ${ + item.date ? 'öðlast gildi ' + formatDate(item.date) : 'öðlast þegar gildi' + }` + impactAffectArray.push(impactAffectedString as HTMLText) + }) + + // Sort the articleKeepArray based on extracted article numbers + articleKeepArray.sort((a, b) => { + const numA = extractArticleNumber(a.text as string) + const numB = extractArticleNumber(b.text as string) + return (numA || 0) - (numB || 0) + }) - return [...nonMatchingStrings, ...matchingStrings] + // Reassign the article numbers in affectedImpacts based on the new order + const updatedImpactAffectArray = impactAffectArray.map((impact, index) => { + const match = impact.match(/(\d+)\. gr\./g) + if (match) { + match.forEach((m, i) => { + const oldNumber = parseInt(m.match(/(\d+)/)![1], 10) + const newNumber = + articleKeepArray.findIndex( + (item) => item.originalIndex === oldNumber - 1, + ) + 1 + impact = impact.replace(m, `${newNumber}. gr.`) as HTMLText + }) + } + return impact as HTMLText + }) + + const uniqueGildistaka = uniq(gildsTakaKeepArray) + const joinedAffected = updatedImpactAffectArray.join('. ') + const gildistakaReturn = flatten([...uniqueGildistaka, joinedAffected]).join( + '', + ) as HTMLText + + return [...articleKeepArray.map((item) => item.text), gildistakaReturn] } const removeRegNamePrefix = (name: string) => { @@ -45,11 +139,15 @@ export const formatAmendingRegTitle = (draft: RegDraftForm) => { const amendingArray = titleArray.filter((item) => item.type === 'amend') const repealArray = titleArray.filter((item) => item.type === 'repeal') - const amendingTitles = amendingArray.map( - (item, i) => - `${i === 0 ? `${PREFIX_AMENDING}` : ''}${removeRegNamePrefix( - item.name, - )} ${removeRegPrefix(item.regTitle)}`, + const amendingTitles = uniq( + amendingArray.map( + (item) => + `${removeRegNamePrefix(item.name)} ${removeRegPrefix(item.regTitle)}`, + ), + ) + + const prefixedAmendingTitles = amendingTitles.map( + (title, i) => `${i === 0 ? `${PREFIX_AMENDING}` : ''}${title}`, ) const repealTitles = repealArray.map( @@ -61,7 +159,9 @@ export const formatAmendingRegTitle = (draft: RegDraftForm) => { return ( PREFIX + - [...amendingTitles, ...repealTitles].join(' og ').replace(/ +(?= )/g, '') + [...prefixedAmendingTitles, ...repealTitles] + .join(' og ') + .replace(/ +(?= )/g, '') ) } @@ -100,6 +200,11 @@ export const formatAmendingRegBody = ( let paragraph = 0 const groupedArticles = groupElementsByArticleTitleFromDiv(diffDiv) + const regNameDisplay = + regName && regName !== 'self' + ? `reglugerðar nr. ${regName}`.replace(/\.$/, '') + : 'reglugerðarinnar' + groupedArticles.forEach((group, i) => { // Get grouped article index to get name of previous grein for addition text. let articleTitle = '' @@ -117,11 +222,6 @@ export const formatAmendingRegBody = ( isAddition: undefined, } - const regNameDisplay = - regName && regName !== 'self' - ? `reglugerðar nr. ${regName}`.replace(/\.$/, '') - : 'reglugerðarinnar' - group.forEach((element) => { let pushHtml = '' as HTMLText @@ -162,10 +262,7 @@ export const formatAmendingRegBody = ( const hasInsert = !!element.querySelector('ins') const isGildistokuGrein = - isParagraph && - /(öðlast|tekur).*gildi|sett.*með.*(?:heimild|stoð)/.test( - (element.textContent || '').toLowerCase(), - ) + isParagraph && isGildisTaka(element.textContent || '') const elementType = isLetterList || isNumberList @@ -335,22 +432,26 @@ export const formatAmendingBodyWithArticlePrefix = ( const impactAdditionArray = Object.entries(impactsArray).map( ([key, impacts]) => { - const impactArray = impacts.map((item, i) => - formatAmendingRegBody( - item.type === 'repeal' || draftImpactLength > 1 ? item.name : '', - item.type === 'repeal', - item.type === 'amend' ? item.diff?.value : undefined, - item.regTitle, - ), - ) - const flatArray = flatten(impactArray) - return flatArray + const impactArray = impacts.map((item, i) => { + return { + formattedRegBody: formatAmendingRegBody( + item.type === 'repeal' || draftImpactLength > 1 ? item.name : '', + item.type === 'repeal', + item.type === 'amend' ? item.diff?.value : undefined, + item.regTitle, + ), + date: item.date.value, + } + }) + return flatten(impactArray) }, ) const additions = flatten(impactAdditionArray) - const returnArray = moveMatchingStringsToEnd(additions) + const htmlForEditor = formatAffectedAndPlaceAffectedAtEnd(additions) + + const returnArray = compact(htmlForEditor) const prependString = returnArray.map( (item, i) =>