= ({\r\n tittel,\r\n id,\r\n verdi,\r\n kommentarVerdi,\r\n hjelpetekst,\r\n maxCharacters,\r\n handleBefaringKommentarVerdiChange,\r\n handleBefaringVerdiChange,\r\n readOnly\r\n}) => {\r\n const [showTooltip, setShowTooltip] = useState(false);\r\n const [isEditingComment, setIsEditingComment] = useState(false);\r\n const [updatedCommentValue, setUpdatedCommentValue] = useState(kommentarVerdi);\r\n const [currentValue, setCurrentValue] = useState(verdi);\r\n\r\n const handleParentChangeOnBlur = () => {\r\n handleBefaringVerdiChange(id, currentValue);\r\n };\r\n const handleSaveComment = () => {\r\n handleBefaringKommentarVerdiChange(id, updatedCommentValue);\r\n };\r\n\r\n const handleChange = (e) => {\r\n setCurrentValue(e.target.value);\r\n };\r\n\r\n const handleCommentChange = (e) => {\r\n setUpdatedCommentValue(e.target.value);\r\n };\r\n\r\n const closePopup = () => {\r\n setIsEditingComment(false);\r\n };\r\n const saveAndClosePopup = () => {\r\n handleSaveComment();\r\n setIsEditingComment(false);\r\n };\r\n\r\n return (\r\n \r\n
\r\n
\r\n
\r\n {!readOnly && (\r\n \r\n )}\r\n \r\n {updatedCommentValue?.length ? (\r\n updatedCommentValue\r\n ) : readOnly ? null : (\r\n Legg til kommentar\r\n )}\r\n \r\n
\r\n
\r\n\r\n
\r\n {readOnly ? (\r\n currentValue ? (\r\n
{currentValue}
\r\n ) : (\r\n
Ingen notater
\r\n )\r\n ) : (\r\n <>\r\n
{currentValue}
\r\n
\r\n
\r\n {currentValue?.length ?? 0}/{maxCharacters}\r\n
\r\n >\r\n )}\r\n
\r\n
\r\n {Boolean(hjelpetekst?.length) && (\r\n
setShowTooltip(!showTooltip)} type=\"noBorder\" title=\"Se info\">\r\n \r\n \r\n )}\r\n
\r\n
setShowTooltip(false)} clickOutsideToClose>\r\n \r\n \r\n
{tittel}
\r\n {hjelpetekst?.length && (\r\n
\r\n {hjelpetekst.map((text) => (\r\n - \r\n {text}\r\n
\r\n ))}\r\n
\r\n )}\r\n
\r\n \r\n
\r\n
\r\n \r\n \r\n\r\n {!readOnly && (\r\n
setIsEditingComment(false)} clickOutsideToClose>\r\n \r\n \r\n\r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n )}\r\n
\r\n );\r\n};\r\nexport default BefaringKommentarBoks;\r\n","// extracted by mini-css-extract-plugin\nexport default {\"VurderingsPopup\":\"Popup-module__VurderingsPopup__zLOU8\",\"InfoPopup\":\"Popup-module__InfoPopup__PvcQz\",\"Text\":\"Popup-module__Text__i1GG7\",\"Spacer\":\"Popup-module__Spacer__mCFeW\",\"Vurdering\":\"Popup-module__Vurdering__n6JJN\",\"ButtonContainer\":\"Popup-module__ButtonContainer__RDDqg\",\"Reset\":\"Popup-module__Reset__V6vF-\",\"Bad\":\"Popup-module__Bad__qyPCI\",\"Medium\":\"Popup-module__Medium__2SHBq\",\"Good\":\"Popup-module__Good__fTbpi\",\"Avstander\":\"Popup-module__Avstander__46gUJ\"};","import React from 'react';\r\nimport { SingelKollektivTransportEntry } from 'types/SingelKollektivTransportEntry';\r\nimport style from './Popup.module.css';\r\nimport Text from 'components/Text/Text';\r\n\r\nexport interface Props {\r\n readonly isLeiesok: boolean;\r\n readonly avstandKollektivTransport: SingelKollektivTransportEntry[];\r\n readonly sykkelparkeringsplasser?: number;\r\n readonly parkeringsplasser?: number;\r\n readonly ladepunkter?: number;\r\n}\r\n\r\nexport default function BeliggenhetPopup({\r\n isLeiesok,\r\n avstandKollektivTransport,\r\n sykkelparkeringsplasser,\r\n parkeringsplasser,\r\n ladepunkter\r\n}: Props) {\r\n return (\r\n <>\r\n \r\n Beliggenhet\r\n \r\n \r\n {avstandKollektivTransport?.map(({ avstandIMeter, kollektivtype }, index) => (\r\n
\r\n \r\n {kollektivtype}: {avstandIMeter} m\r\n \r\n
\r\n ))}\r\n
\r\n {parkeringsplasser !== null && isLeiesok && (\r\n \r\n \r\n Antall parkeringsplasser: {parkeringsplasser} stk\r\n \r\n
\r\n )}\r\n {sykkelparkeringsplasser !== null && isLeiesok && (\r\n \r\n \r\n Antall sykkelparkering: {sykkelparkeringsplasser} stk\r\n \r\n
\r\n )}\r\n {ladepunkter !== null && isLeiesok && (\r\n \r\n \r\n Antall ladepunkter: {ladepunkter} stk\r\n \r\n
\r\n )}\r\n >\r\n );\r\n}\r\n","import React from 'react';\r\nimport { ArealEtPlan } from 'types/ArealEtPlan';\r\nimport style from './Popup.module.css';\r\nimport Text from 'components/Text/Text';\r\n\r\nexport interface Props {\r\n readonly totaltAreal?: number;\r\n readonly ledigAreal?: number;\r\n readonly arealPerPlan?: ArealEtPlan[];\r\n readonly universellUtforming?: string;\r\n readonly bebygdStatus?: string;\r\n readonly tilbudtAreal?: number;\r\n readonly utbyggingspotensialeBTA?: number;\r\n}\r\n\r\nexport default function FleksibilitetPopup({\r\n totaltAreal,\r\n ledigAreal,\r\n arealPerPlan,\r\n universellUtforming,\r\n bebygdStatus,\r\n tilbudtAreal,\r\n utbyggingspotensialeBTA\r\n}: Props) {\r\n return (\r\n <>\r\n \r\n Fleksibilitet\r\n \r\n\r\n {!!totaltAreal && (\r\n \r\n \r\n Totalt areal:{' '}\r\n \r\n {totaltAreal} m2\r\n \r\n \r\n
\r\n )}\r\n {!!ledigAreal && (\r\n \r\n \r\n Ledig areal:{' '}\r\n \r\n {ledigAreal} m2\r\n \r\n \r\n
\r\n )}\r\n\r\n \r\n {arealPerPlan?.map(({ areal, plan }, index) => (\r\n
\r\n \r\n {plan} etasje:{' '}\r\n \r\n {areal} m2\r\n \r\n \r\n
\r\n ))}\r\n
\r\n\r\n {!!universellUtforming && (\r\n \r\n \r\n Universell Utforming: {universellUtforming}\r\n \r\n
\r\n )}\r\n\r\n {!!tilbudtAreal && (\r\n \r\n \r\n Tilbudt areal:\r\n {tilbudtAreal}\r\n \r\n
\r\n )}\r\n\r\n {!!utbyggingspotensialeBTA && (\r\n \r\n \r\n Utbyggingspotensiale:\r\n {utbyggingspotensialeBTA}\r\n \r\n
\r\n )}\r\n\r\n {!!bebygdStatus && (\r\n \r\n \r\n Bebygd/ubebygd:\r\n {bebygdStatus}\r\n \r\n
\r\n )}\r\n >\r\n );\r\n}\r\n","import { numberWithSpaces } from 'js/format-helper';\r\nimport React from 'react';\r\nimport Text from 'components/Text/Text';\r\n\r\nexport interface Props {\r\n readonly prisKvmUtenTiltak?: number;\r\n readonly prisKvmMedTiltak?: number;\r\n readonly felleskostKvm?: number;\r\n readonly parkeringsplasskost?: number;\r\n readonly sykkelplasskost?: number;\r\n readonly kostKantineBidrag?: number;\r\n readonly mvaKompensasjonKvm?: number;\r\n readonly paslagFellesarealiProsent?: number;\r\n}\r\n\r\nexport default function LeieprisPopup({\r\n prisKvmUtenTiltak,\r\n prisKvmMedTiltak,\r\n felleskostKvm,\r\n parkeringsplasskost,\r\n sykkelplasskost,\r\n kostKantineBidrag,\r\n mvaKompensasjonKvm,\r\n paslagFellesarealiProsent\r\n}: Props) {\r\n return (\r\n <>\r\n \r\n Leiepris\r\n \r\n\r\n \r\n Pris med tiltak:\r\n {' ' + numberWithSpaces(prisKvmMedTiltak)} kr\r\n \r\n \r\n Pris uten tiltak:\r\n {' ' + numberWithSpaces(prisKvmUtenTiltak)} kr\r\n \r\n\r\n \r\n \r\n Felleskost per m2 BTA: {numberWithSpaces(felleskostKvm)} kr\r\n \r\n
\r\n\r\n \r\n \r\n Pr P-plass: {numberWithSpaces(parkeringsplasskost)} kr\r\n \r\n
\r\n\r\n \r\n \r\n Pr sykkelplass: {numberWithSpaces(sykkelplasskost)} kr\r\n \r\n
\r\n\r\n \r\n \r\n Kantinebidrag pr ansatt:\r\n {numberWithSpaces(kostKantineBidrag)} kr\r\n \r\n
\r\n\r\n \r\n \r\n MVA kompensasjon per m2 BTA:{' '}\r\n {numberWithSpaces(mvaKompensasjonKvm)} kr\r\n \r\n
\r\n \r\n \r\n Påslag for fellesareal i prosent: {paslagFellesarealiProsent} %\r\n \r\n
\r\n >\r\n );\r\n}\r\n","import SelectField, { Choice } from 'components/SelectField/SelectField';\r\nimport React from 'react';\r\nimport { components } from 'react-select';\r\nimport style from './Energimerke.module.css';\r\n\r\nconst colorLookup = {\r\n red: '#c7262b',\r\n orange: '#f67821',\r\n yellow: '#e8d056',\r\n chartreuse: '#7fc241',\r\n green: '#039149'\r\n};\r\n\r\nconst colors = ['red', 'orange', 'yellow', 'chartreuse', 'green'] as const;\r\nconst letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G'] as const;\r\n\r\ntype EnergiMerkeValueLabel = { value: EnergiLetterColor; label: string };\r\nexport type Letter = typeof letters[number];\r\nexport type Color = keyof typeof colorLookup;\r\n\r\nexport interface EnergiLetterColor {\r\n readonly letter: Letter;\r\n readonly color: Color;\r\n}\r\n\r\nconst options: EnergiMerkeValueLabel[] = [];\r\n\r\nfor (let i = 0; i < 7; i++) {\r\n for (let c = 0; c < 5; c++) {\r\n options.push({\r\n value: { letter: letters[i], color: colors[c] },\r\n label: i + '-' + c\r\n });\r\n }\r\n}\r\n\r\nconst MenuList = (props) => {\r\n return (\r\n \r\n {props.children}
\r\n \r\n );\r\n};\r\n\r\nexport const Merke = ({ color, letter }: EnergiLetterColor) => (\r\n \r\n {letter}\r\n
\r\n);\r\n\r\nconst Option = (props) => (\r\n props.setValue(props.value)}>\r\n \r\n
\r\n);\r\n\r\nconst SingleValue = (props) => ;\r\n\r\nexport interface Props {\r\n value?: EnergiLetterColor;\r\n onChange(value?: EnergiLetterColor): void;\r\n isClearable?: boolean;\r\n readonly feedback?: string;\r\n readonly validationState?: 'error' | null;\r\n readonly feedbackMargin?: boolean;\r\n}\r\n\r\nexport default function Energimerke({\r\n onChange,\r\n value,\r\n isClearable,\r\n ...props\r\n}: Props) {\r\n return (\r\n \r\n ) => void\r\n }\r\n choices={options}\r\n components={{\r\n MenuList,\r\n Option,\r\n SingleValue\r\n }}\r\n isSearchable={false}\r\n isClearable={isClearable}\r\n {...props}\r\n />\r\n
\r\n );\r\n}\r\n","// extracted by mini-css-extract-plugin\nexport default {\"energimerke\":\"Energimerke-module__energimerke__3-tpr\",\"merke\":\"Energimerke-module__merke__KQggG\",\"menuList\":\"Energimerke-module__menuList__Qahal\",\"option\":\"Energimerke-module__option__pSlo2\"};","import { Color, Letter, Merke } from 'components/Energimerke/Energimerke';\r\nimport React from 'react';\r\nimport { Fildata } from 'types/Fildata';\r\nimport Text from 'components/Text/Text';\r\n\r\nexport interface Props {\r\n readonly energimerke: string;\r\n readonly energimerkeFarge: string;\r\n readonly planlagtEnergimerke?: string;\r\n readonly planlagtEnergimerkeFarge?: string;\r\n readonly energiattest?: Fildata;\r\n readonly miljosertifisert: string;\r\n readonly kwh?: number;\r\n}\r\n\r\nexport default function MiljoPopup({\r\n energimerke,\r\n energimerkeFarge,\r\n planlagtEnergimerke,\r\n planlagtEnergimerkeFarge,\r\n energiattest,\r\n miljosertifisert,\r\n kwh\r\n}: Props) {\r\n return (\r\n <>\r\n \r\n Miljø\r\n \r\n\r\n \r\n \r\n Energimerke: \r\n \r\n
\r\n\r\n {planlagtEnergimerke && planlagtEnergimerkeFarge && (\r\n \r\n \r\n Planlagt energimerke: {' '}\r\n \r\n
\r\n )}\r\n\r\n \r\n
\r\n Energiattest:{' '}\r\n {energiattest !== null ? (\r\n \r\n Vedlagt\r\n \r\n ) : (\r\n Ikke vedlagt\r\n )}\r\n \r\n
\r\n\r\n \r\n \r\n Miljøsertifisert: {miljosertifisert}\r\n \r\n
\r\n\r\n {!!kwh && (\r\n \r\n \r\n Kwh: {kwh} kwh\r\n \r\n
\r\n )}\r\n >\r\n );\r\n}\r\n","import { shortDateString } from 'js/date-helper';\r\nimport React from 'react';\r\nimport Text from 'components/Text/Text';\r\n\r\nexport interface Props {\r\n readonly generellInfoLedigFraUtc?: string;\r\n readonly gjennomforingstidTilByggeklar?: string;\r\n}\r\n\r\nexport default function OvertakelsePopup({ generellInfoLedigFraUtc, gjennomforingstidTilByggeklar }: Props) {\r\n return (\r\n <>\r\n \r\n Overtakelse\r\n \r\n\r\n {!!generellInfoLedigFraUtc && (\r\n \r\n \r\n Ledig fra: {shortDateString(generellInfoLedigFraUtc)}\r\n \r\n
\r\n )}\r\n\r\n {!!gjennomforingstidTilByggeklar && (\r\n \r\n \r\n Gjennomføringstid til tom er byggeklar: {gjennomforingstidTilByggeklar}\r\n \r\n
\r\n )}\r\n >\r\n );\r\n}\r\n","import cn from 'classnames';\r\nimport React, { useCallback } from 'react';\r\nimport { BsArrowCounterclockwise } from 'react-icons/bs';\r\nimport Button from 'components/Button/Button';\r\nimport style from './Popup.module.css';\r\nimport Text from 'components/Text/Text';\r\n\r\nexport interface Props {\r\n readonly score: number;\r\n readonly label?: string;\r\n readonly titleComponent?: React.ReactNode;\r\n readonly column?: boolean;\r\n onChange(score: number): void;\r\n}\r\n\r\nexport function Vurdering({ label = 'Vurdering', titleComponent, score, onChange, column }: Props) {\r\n const unset = useCallback(() => onChange(0), [onChange]);\r\n const setBad = useCallback(() => onChange(1), [onChange]);\r\n const setMedium = useCallback(() => onChange(2), [onChange]);\r\n const setGood = useCallback(() => onChange(3), [onChange]);\r\n\r\n return (\r\n \r\n {titleComponent || (\r\n
\r\n {label}:{' '}\r\n \r\n )}\r\n\r\n
\r\n {!!score && (\r\n \r\n )}\r\n\r\n \r\n\r\n \r\n\r\n \r\n
\r\n
\r\n );\r\n}\r\n","import TriPie from 'components/TriPie/TriPie';\r\nimport React, { PropsWithChildren } from 'react';\r\nimport Panel from 'components/Panel/Panel';\r\nimport style from './Popup.module.css';\r\nimport { Vurdering } from './Vurdering';\r\n\r\nexport interface Props {\r\n readonly kalkulert: number;\r\n readonly overstyrt: number;\r\n readonly visVurdering: boolean;\r\n readonly overstyrVurdering: boolean;\r\n onChange(value: number): void;\r\n}\r\n\r\nconst VurderingsPopup = ({\r\n kalkulert,\r\n overstyrt,\r\n visVurdering,\r\n overstyrVurdering,\r\n onChange,\r\n children\r\n}: PropsWithChildren) => {\r\n if (visVurdering) {\r\n return (\r\n \r\n \r\n\r\n \r\n {children}\r\n
\r\n {overstyrVurdering &&
}\r\n
\r\n \r\n );\r\n } else {\r\n return (\r\n \r\n {children}
\r\n \r\n );\r\n }\r\n};\r\n\r\nVurderingsPopup.displayName = 'VurderingsPopup';\r\n\r\nexport default VurderingsPopup;\r\n","/* eslint-disable react/display-name */\r\nimport Popup from 'components/Popup/Popup';\r\nimport TriPie from 'components/TriPie/TriPie';\r\nimport { post } from 'js/api-helper';\r\nimport { useOnChange } from 'js/hooks';\r\nimport React, { useCallback, useState, useMemo } from 'react';\r\nimport { BsBoxArrowUpRight } from 'react-icons/bs';\r\nimport { Score as ScoreType } from 'types/Score';\r\nimport style from './Score.module.css';\r\nimport VurderingsPopup from './Popups/VurderingsPopup';\r\nimport Text from 'components/Text/Text';\r\n\r\ninterface IScore {\r\n visVurdering: boolean;\r\n hideExpand?: boolean;\r\n title: string;\r\n score: ScoreType;\r\n children: JSX.Element | null;\r\n readonly overstyrVurderingUrl?: string;\r\n}\r\n\r\nconst ScoreUnit = ({ visVurdering, hideExpand, children, title, score, overstyrVurderingUrl }: IScore) => {\r\n const [popupOpen, setPopupOpen] = useState(false);\r\n\r\n const overstyrVurdering = useCallback(\r\n async (type: string, vurdering: number) => {\r\n await post(overstyrVurderingUrl as string, { type, vurdering });\r\n },\r\n [overstyrVurderingUrl]\r\n );\r\n\r\n const [overstyrtScore, setOverstyrtScore] = useState(score.overstyrtScore);\r\n\r\n useOnChange(overstyrVurdering, [score.type, overstyrtScore]);\r\n\r\n const childrenWithProps = useMemo(\r\n () =>\r\n React.Children.map(children, (child) => {\r\n // checking isValidElement is the safe way and avoids a typescript error too\r\n if (React.isValidElement(child)) {\r\n return React.cloneElement(child, { onChange: setOverstyrtScore });\r\n }\r\n return child;\r\n }),\r\n [children, setOverstyrtScore]\r\n );\r\n\r\n return (\r\n <>\r\n setPopupOpen(!hideExpand && true)}\r\n >\r\n {!hideExpand &&
}\r\n
\r\n {title}\r\n \r\n
\r\n {overstyrtScore !== 0 && overstyrtScore !== score.kalkulertScore ? 'Justert' : ' '}\r\n \r\n
\r\n {visVurdering && }\r\n
\r\n
\r\n\r\n setPopupOpen(false)}>\r\n \r\n {childrenWithProps}\r\n \r\n \r\n >\r\n );\r\n};\r\n\r\nexport default ScoreUnit;\r\n","// extracted by mini-css-extract-plugin\nexport default {\"ScoreUnit\":\"Score-module__ScoreUnit__prD4Y\",\"TriPieWrapper\":\"Score-module__TriPieWrapper__F7dF8\",\"Rating\":\"Score-module__Rating__J+xs4\",\"triPieSvg\":\"Score-module__triPieSvg__fSP5K\",\"justertText\":\"Score-module__justertText__Hw8r1\",\"RatingMultiRows\":\"Score-module__RatingMultiRows__3gceE\",\"expandIcon\":\"Score-module__expandIcon__eXfkG\"};","import React from 'react';\r\nimport Text from 'components/Text/Text';\r\nimport { numberWithSpaces } from 'js/format-helper';\r\n\r\nexport interface Props {\r\n readonly prisKvmMedTiltak?: number;\r\n readonly prisKvmUtenTiltak?: number;\r\n}\r\n\r\nexport default function TomteprisPopup({ prisKvmMedTiltak, prisKvmUtenTiltak }: Props) {\r\n return (\r\n <>\r\n \r\n Tomtepris\r\n \r\n\r\n \r\n Pris:\r\n {numberWithSpaces(prisKvmMedTiltak)} kr\r\n \r\n >\r\n );\r\n}\r\n","/* eslint-disable react/display-name */\r\nimport React from 'react';\r\nimport { ArealEtPlan } from 'types/ArealEtPlan';\r\nimport { Score as ScoreType } from 'types/Score';\r\nimport { SingelKollektivTransportEntry } from 'types/SingelKollektivTransportEntry';\r\nimport BeliggenhetPopup from './Popups/BeliggenhetPopup';\r\nimport FleksibilitetPopup from './Popups/FleksibilitetPopup';\r\nimport LeieprisPopup from './Popups/LeieprisPopup';\r\nimport MiljoPopup from './Popups/MiljoPopup';\r\nimport OvertakelsePopup from './Popups/OvertakelsePopup';\r\nimport style from './Score.module.css';\r\nimport ScoreUnit from './ScoreUnit';\r\nimport { Miljodata } from 'types/Miljodata';\r\nimport { Parkeringsdata } from 'types/Parkeringsdata';\r\nimport TomteprisPopup from './Popups/TomteprisPopup';\r\nimport Text from 'components/Text/Text';\r\n\r\ninterface IScore {\r\n visVurdering: boolean;\r\n hideExpand?: boolean;\r\n isLeiesok: boolean;\r\n readonly scores: ScoreType[];\r\n readonly avstandKollektivTransport: SingelKollektivTransportEntry[];\r\n readonly overstyrVurderingUrl?: string;\r\n readonly generellInfoLedigFraUtc?: string;\r\n readonly gjennomforingstidTilByggeklar?: string;\r\n readonly miljoData?: Miljodata;\r\n readonly parkeringsData?: Parkeringsdata;\r\n readonly universellUtforming?: string;\r\n readonly totaltAreal?: number;\r\n readonly ledigAreal?: number;\r\n readonly arealPerPlan?: ArealEtPlan[];\r\n readonly prisKvmMedTiltak?: number;\r\n readonly prisKvmUtenTiltak?: number;\r\n readonly felleskostKvm?: number;\r\n readonly mvaKompensasjonKvm?: number;\r\n readonly paslagFellesarealiProsent?: number;\r\n readonly kostKantineBidrag?: number;\r\n readonly overstyrtScoreHelhetsvurdering?: number;\r\n readonly bebygdStatus?: string;\r\n readonly reguleringsstatus?: string;\r\n readonly grunnforhold?: string;\r\n readonly infrastruktur?: string;\r\n readonly tilbudtAreal?: number;\r\n readonly utbyggingspotensialeBTA?: number;\r\n}\r\n\r\nconst ScoreRow = ({\r\n isLeiesok,\r\n visVurdering,\r\n hideExpand,\r\n scores,\r\n overstyrVurderingUrl,\r\n avstandKollektivTransport,\r\n miljoData,\r\n parkeringsData,\r\n generellInfoLedigFraUtc,\r\n totaltAreal,\r\n ledigAreal,\r\n gjennomforingstidTilByggeklar,\r\n arealPerPlan,\r\n universellUtforming,\r\n prisKvmUtenTiltak,\r\n prisKvmMedTiltak,\r\n felleskostKvm,\r\n kostKantineBidrag,\r\n mvaKompensasjonKvm,\r\n paslagFellesarealiProsent,\r\n bebygdStatus,\r\n tilbudtAreal,\r\n utbyggingspotensialeBTA,\r\n reguleringsstatus,\r\n grunnforhold,\r\n infrastruktur\r\n}: IScore) => {\r\n const getPopupComponent = (type) => {\r\n switch (type) {\r\n case 'Beliggenhet':\r\n return (\r\n \r\n );\r\n case 'Miljø':\r\n return (\r\n \r\n );\r\n case 'Overtakelse':\r\n return (\r\n \r\n );\r\n case 'Fleksibilitet':\r\n return (\r\n \r\n );\r\n case 'Tomtepris':\r\n return ;\r\n case 'Leiepris':\r\n return (\r\n \r\n );\r\n case 'Regulering':\r\n return (\r\n <>\r\n \r\n Regulering\r\n \r\n {reguleringsstatus}\r\n >\r\n );\r\n case 'Infrastruktur':\r\n return (\r\n <>\r\n \r\n Infrastruktur\r\n \r\n {infrastruktur}\r\n >\r\n );\r\n case 'Grunnforhold':\r\n return (\r\n <>\r\n \r\n Grunnforhold\r\n \r\n {grunnforhold}\r\n >\r\n );\r\n default:\r\n return null;\r\n }\r\n };\r\n\r\n return (\r\n \r\n {scores?.map((score, index) => {\r\n const Component = getPopupComponent(score.type);\r\n return (\r\n \r\n {Component}\r\n \r\n );\r\n })}\r\n
\r\n );\r\n};\r\n\r\nexport default ScoreRow;\r\n","// extracted by mini-css-extract-plugin\nexport default {\"wrapper\":\"BefaringSide-module__wrapper__ZpPFu\",\"titleWrapper\":\"BefaringSide-module__titleWrapper__F2dzb\",\"title\":\"BefaringSide-module__title__ka4hw\",\"recindLabel\":\"BefaringSide-module__recindLabel__EfgeO\",\"margin\":\"BefaringSide-module__margin__Jlz5B\",\"recommendedBox\":\"BefaringSide-module__recommendedBox__b5adP\",\"befaringH2\":\"BefaringSide-module__befaringH2__wruxG\",\"forbeholdBox\":\"BefaringSide-module__forbeholdBox__zmeSa\",\"forbeholdContent\":\"BefaringSide-module__forbeholdContent__h7r10\",\"actionsBar\":\"BefaringSide-module__actionsBar__akdo0\"};","// extracted by mini-css-extract-plugin\nexport default {\"ImageUploadGrid\":\"ImageUploadGrid-module__ImageUploadGrid__SVuRE\",\"noRows\":\"ImageUploadGrid-module__noRows__dCxKH\",\"oneRow\":\"ImageUploadGrid-module__oneRow__9GHMa\",\"twoRows\":\"ImageUploadGrid-module__twoRows__YmBqb\",\"imageItem\":\"ImageUploadGrid-module__imageItem__MjaDG\",\"imageItemReadOnly\":\"ImageUploadGrid-module__imageItemReadOnly__t0ohK\",\"imageFileUploadInput\":\"ImageUploadGrid-module__imageFileUploadInput__xYO13\",\"image\":\"ImageUploadGrid-module__image__49YoM\",\"imageButton\":\"ImageUploadGrid-module__imageButton__qvEcK\",\"expandButton\":\"ImageUploadGrid-module__expandButton__NS3Y4\",\"deleteButton\":\"ImageUploadGrid-module__deleteButton__1sq-r\",\"editButton\":\"ImageUploadGrid-module__editButton__vniPl\",\"emptyAddComment\":\"ImageUploadGrid-module__emptyAddComment__kzeyo\",\"imageBoxWrapperHiddenPrint\":\"ImageUploadGrid-module__imageBoxWrapperHiddenPrint__azsaw\",\"uploadIconWrapper\":\"ImageUploadGrid-module__uploadIconWrapper__nMI0o\",\"imageItemEmpty\":\"ImageUploadGrid-module__imageItemEmpty__ctDmk\"};","import { upload, post, ValidationError } from 'js/api-helper';\r\nimport React, { useCallback, useEffect, useState } from 'react';\r\nimport { AiOutlineSync, AiOutlineUpload } from 'react-icons/ai';\r\nimport style from './ImageUploadGrid.module.css';\r\nimport { Fildata } from 'types/Fildata';\r\nimport { BsBoxArrowUpRight } from 'react-icons/bs';\r\nimport Popup from 'components/Popup/Popup';\r\nimport cn from 'classnames';\r\nimport IconReactIcons, { IconTypes } from 'components/Icon/IconReactIcons';\r\n\r\nexport interface Props {\r\n readonly destinationUrl: string;\r\n readonly bildeFil: Fildata;\r\n readonly onUploadComplete?: (file: Fildata, index: number) => void;\r\n readOnly?: boolean;\r\n index: number;\r\n handleDeleteImg: (id: string) => void;\r\n}\r\n\r\nexport default function ImageUploadBox({ destinationUrl, onUploadComplete, bildeFil, readOnly, index, handleDeleteImg }: Props) {\r\n const [isBusy, setBusy] = useState(false);\r\n const [uploadFailedMessage, setUploadFailedMessage] = useState();\r\n const [imageUrl, setImageUrl] = useState(bildeFil?.nedlastingslenke || '');\r\n const [popupImage, setPopupImage] = useState(false);\r\n\r\n useEffect(() => {\r\n setImageUrl(bildeFil?.nedlastingslenke || '');\r\n }, [bildeFil]);\r\n\r\n const handleUpload = useCallback(\r\n async (files: globalThis.File[]) => {\r\n setBusy(true);\r\n setUploadFailedMessage(undefined);\r\n try {\r\n for (const file of files) {\r\n const data = new FormData();\r\n data.append('file', file);\r\n try {\r\n console.log({ data, file });\r\n const newImg = URL.createObjectURL(file);\r\n setImageUrl(newImg);\r\n const result = await upload(destinationUrl, data);\r\n onUploadComplete?.(result, index);\r\n } catch (error) {\r\n if (error instanceof ValidationError) {\r\n setUploadFailedMessage(error['file']);\r\n return;\r\n }\r\n }\r\n }\r\n } finally {\r\n // There is a warning in the devtools because of this line; ignore it.\r\n // If this component is unmounted because of the onUploadComplete call above,\r\n // then it's too late to update the state here. It warns that it's a memory leak,\r\n // but it's not really, so nothing to worry about.\r\n setBusy(false);\r\n }\r\n },\r\n [destinationUrl, onUploadComplete]\r\n );\r\n\r\n const handleDeleteImgIfId = () => {\r\n if (bildeFil.id) {\r\n handleDeleteImg(bildeFil.id);\r\n } else {\r\n setImageUrl('');\r\n }\r\n };\r\n\r\n return (\r\n <>\r\n {uploadFailedMessage && (\r\n \r\n {uploadFailedMessage}\r\n
\r\n )}\r\n\r\n \r\n >\r\n );\r\n}\r\n","import { post } from 'js/api-helper';\r\nimport React, { FC, useMemo, useState } from 'react';\r\nimport { Fildata } from 'types/Fildata';\r\nimport ImageUploadBox from './ImageUploadBox';\r\nimport style from './ImageUploadGrid.module.css';\r\nexport interface IImageUploadGrid {\r\n bildeListe: Fildata[];\r\n imageUploadUrl: string;\r\n readOnly?: boolean;\r\n readonly slettBefaringBildeApi: string;\r\n}\r\n\r\nconst ImageUploadGrid: FC = ({\r\n bildeListe,\r\n imageUploadUrl,\r\n readOnly,\r\n slettBefaringBildeApi\r\n}) => {\r\n const [currentBildeListe, setCurrentBildeListe] = useState(\r\n bildeListe\r\n );\r\n const handleFile = (file: Fildata, index: number): void => {\r\n /* eslint-disable no-console */\r\n const newBildeListe = [...currentBildeListe];\r\n newBildeListe[index] = file;\r\n setCurrentBildeListe(newBildeListe);\r\n };\r\n const imageRowClass = useMemo(() => {\r\n const images = currentBildeListe?.filter((bilde) => bilde?.nedlastingslenke)\r\n .length;\r\n if (!readOnly) return '';\r\n else if (images === 0) return style.noRows;\r\n else if (images === 1) return style.oneRow;\r\n else if (images === 2 || images === 3) return style.twoRows;\r\n else return '';\r\n // if (!hasImage && readOnly) return true;\r\n // else return false;\r\n }, [currentBildeListe]);\r\n\r\n const handleDeleteImg = async (id) => {\r\n try {\r\n await post(`${slettBefaringBildeApi}?bildeId=${id}`);\r\n const updatedBildeListe = currentBildeListe.map((bilde) =>\r\n bilde.id === id\r\n ? {\r\n id: '',\r\n nedlastingslenke: '',\r\n visningsnavn: ''\r\n }\r\n : bilde\r\n );\r\n setCurrentBildeListe(updatedBildeListe);\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n };\r\n\r\n // if (stopRender) return null;\r\n return (\r\n \r\n {currentBildeListe?.map((bilde, index) => {\r\n if (readOnly && !bilde?.nedlastingslenke) return null;\r\n else\r\n return (\r\n \r\n );\r\n })}\r\n
\r\n );\r\n};\r\n\r\nImageUploadGrid.defaultProps = {\r\n bildeListe: [\r\n {\r\n id: '',\r\n nedlastingslenke: '',\r\n visningsnavn: ''\r\n },\r\n {\r\n id: '',\r\n nedlastingslenke: '',\r\n visningsnavn: ''\r\n },\r\n {\r\n id: '',\r\n nedlastingslenke: '',\r\n visningsnavn: ''\r\n },\r\n {\r\n id: '',\r\n nedlastingslenke: '',\r\n visningsnavn: ''\r\n },\r\n {\r\n id: '',\r\n nedlastingslenke: '',\r\n visningsnavn: ''\r\n },\r\n {\r\n id: '',\r\n nedlastingslenke: '',\r\n visningsnavn: ''\r\n }\r\n ]\r\n};\r\nexport default ImageUploadGrid;\r\n","import React, { FC, useState } from 'react';\r\nimport style from './BefaringKommentarBoks.module.css';\r\nimport { BefaringsVurdering } from '../BefaringSide';\r\n\r\nexport interface IBefaringAnbefalingBoks {\r\n onChange?: () => void;\r\n readOnly?: boolean;\r\n tittel: string;\r\n id: string;\r\n verdi: string;\r\n vurdering: BefaringsVurdering;\r\n handleAnbefalingKommentarChange: (id: string, value: string) => void;\r\n handleAnbefaling: (boolean) => void;\r\n}\r\n\r\nconst BefaringAnbefalingBoks: FC = ({\r\n tittel,\r\n id,\r\n verdi,\r\n vurdering,\r\n handleAnbefalingKommentarChange,\r\n handleAnbefaling,\r\n readOnly\r\n}) => {\r\n const [currentValue, setCurrentValue] = useState(verdi);\r\n\r\n const handleParentChangeOnBlur = () => {\r\n handleAnbefalingKommentarChange(id, currentValue);\r\n };\r\n\r\n const handleChange = (e) => {\r\n setCurrentValue(e.target.value);\r\n };\r\n\r\n return (\r\n \r\n
\r\n
\r\n
\r\n
\r\n\r\n
\r\n {readOnly ? (\r\n currentValue ? (\r\n
{currentValue}
\r\n ) : (\r\n
Ingen notater
\r\n )\r\n ) : (\r\n
\r\n )}\r\n
\r\n
\r\n
\r\n );\r\n};\r\nexport default BefaringAnbefalingBoks;\r\n","import React, { FC, useState } from 'react';\r\nimport { Befaring } from 'types/Befaring';\r\nimport ScoreRow from 'components/ScoreRow/ScoreRow';\r\nimport BefaringHeader from './BefaringHeader/BefaringHeader';\r\nimport BefaringKalkulator from './BefaringKalkulator/BefaringKalkulator';\r\nimport BefaringKommentarBoks from './BefaringKommentarBoks/BefaringKommentarBoks';\r\nimport style from './BefaringSide.module.css';\r\nimport ImageUploadGrid from './ImageUploadGrid/ImageUploadGrid';\r\nimport Button from 'components/Button/Button';\r\nimport { post } from 'js/api-helper';\r\nimport { AiOutlineSync } from 'react-icons/ai';\r\nimport BefaringAnbefalingBoks from './BefaringKommentarBoks/BefaringAnbefalingBoks';\r\nimport { ProsjektKriterier } from 'types/ProsjektKriterier';\r\nimport { LinkItem } from 'types/LinkItem';\r\nimport PageLinkMenu from 'components/PageLinkMenu/PageLinkMenu';\r\nexport interface BefaringSide {\r\n readonly befaring: Befaring;\r\n readonly oppdaterBefaringUrl: string;\r\n readonly overstyrVurderingUrl: string;\r\n readonly slettBefaringBildeApi: string;\r\n readonly bildeOpplastingsUrl: string;\r\n readonly visKalkulator: boolean;\r\n readonly readOnly?: boolean;\r\n readonly prosjektKriterier: ProsjektKriterier;\r\n readonly pageLinks?: LinkItem[];\r\n readonly erTrukket?: boolean;\r\n}\r\n\r\nexport enum BefaringsVurdering {\r\n UNSET = -1,\r\n ANBEFALES = 0,\r\n ANBEFALES_MED_ANMERKNING = 1,\r\n ANBEFALES_IKKE = 2\r\n}\r\n\r\nconst BefaringSide: FC = ({\r\n visKalkulator,\r\n befaring,\r\n overstyrVurderingUrl,\r\n oppdaterBefaringUrl,\r\n bildeOpplastingsUrl,\r\n readOnly,\r\n prosjektKriterier,\r\n slettBefaringBildeApi,\r\n pageLinks,\r\n erTrukket\r\n}) => {\r\n const {\r\n tittel,\r\n befaringKommentarer,\r\n ledigAreal,\r\n kvmPris,\r\n mvaKompensasjonKvm,\r\n felleskostKvm,\r\n estimertTotalpris,\r\n utleiemegler,\r\n utleier,\r\n fremutleier,\r\n datoForBefaring,\r\n beliggenhet,\r\n tilstede,\r\n bildeListe,\r\n erAnbefalt,\r\n erVurdert,\r\n erAnbefaltMedAnmerkning,\r\n befaringNr,\r\n oppsummeringsVerdi\r\n } = befaring;\r\n\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [hasError, setHasError] = useState(false);\r\n const [saveCompleted, setSaveCompleted] = useState(false);\r\n\r\n const [editBefaring, setEditBefaring] = useState({\r\n tittel,\r\n kvmPris,\r\n mvaKompensasjonKvm,\r\n ledigAreal,\r\n felleskostKvm,\r\n oppsummeringsVerdi,\r\n fremutleier,\r\n datoForBefaring,\r\n beliggenhet,\r\n tilstede,\r\n befaringKommentarer,\r\n erAnbefalt,\r\n erVurdert,\r\n erAnbefaltMedAnmerkning\r\n });\r\n\r\n const handleBefaringChange = (id, value) => {\r\n setSaveCompleted(false);\r\n\r\n setEditBefaring({\r\n ...editBefaring,\r\n [id]: value\r\n });\r\n };\r\n\r\n const handleBefaringVerdiChange = (id, value) => {\r\n setSaveCompleted(false);\r\n\r\n setEditBefaring({\r\n ...editBefaring,\r\n befaringKommentarer: editBefaring.befaringKommentarer.map((befaringKommentar) => {\r\n if (befaringKommentar.id === id) {\r\n return {\r\n ...befaringKommentar,\r\n verdi: value\r\n };\r\n } else return befaringKommentar;\r\n })\r\n });\r\n };\r\n\r\n const handleBefaringKommentarVerdiChange = (id, value) => {\r\n setSaveCompleted(false);\r\n\r\n setEditBefaring({\r\n ...editBefaring,\r\n befaringKommentarer: editBefaring.befaringKommentarer.map((befaringKommentar) => {\r\n if (befaringKommentar.id === id) {\r\n return {\r\n ...befaringKommentar,\r\n kommentarVerdi: value\r\n };\r\n } else return befaringKommentar;\r\n })\r\n });\r\n };\r\n\r\n const submitBefaring = async () => {\r\n setIsLoading(true);\r\n try {\r\n await post(oppdaterBefaringUrl, editBefaring);\r\n setSaveCompleted(true);\r\n setHasError(false);\r\n } catch (error) {\r\n setHasError(true);\r\n setSaveCompleted(false);\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n };\r\n\r\n const handleAnbefalingKommentarChange = (id, value) => {\r\n setEditBefaring({\r\n ...editBefaring,\r\n oppsummeringsVerdi: value\r\n });\r\n };\r\n\r\n const handleAnbefaling = (vurdering: BefaringsVurdering) => {\r\n setEditBefaring({\r\n ...editBefaring,\r\n erVurdert: true,\r\n erAnbefalt: vurdering == BefaringsVurdering.ANBEFALES,\r\n erAnbefaltMedAnmerkning: vurdering == BefaringsVurdering.ANBEFALES_MED_ANMERKNING\r\n });\r\n };\r\n\r\n return (\r\n \r\n
Befaring nr: {befaringNr}\r\n {tittel && (\r\n
\r\n
{editBefaring.tittel}
\r\n {erTrukket && Trukket}\r\n \r\n )}\r\n
\r\n {readOnly && (\r\n
\r\n \r\n
Forbehold
\r\n
\r\n Vi fremhever at rapporten er basert på de opplysningene som tilbyderne har gitt om sine respektive leieobjekter, og\r\n at leiepriser inkl. mva-kompensasjon må betraktes som uforpliktende prisantydninger.\r\n
\r\n
\r\n \r\n )}\r\n {pageLinks && pageLinks?.length > 0 &&
}\r\n
\r\n \r\n \r\n\r\n
\r\n \r\n \r\n
\r\n \r\n \r\n
\r\n \r\n\r\n {!!prosjektKriterier?.malbilde &&
"{prosjektKriterier.malbilde}"
}\r\n\r\n {befaringKommentarer?.map((kommentar) => (\r\n
\r\n ))}\r\n
\r\n\r\n
\r\n {hasError && !isLoading &&
Noe gikk galt
}\r\n\r\n {saveCompleted && !isLoading &&
Lagring fullført
}\r\n\r\n {!!isLoading &&
}\r\n
\r\n
\r\n\r\n {erAnbefalt && (\r\n
\r\n Anbefales til konkurranse\r\n
\r\n )}\r\n
\r\n {!!(visKalkulator && prosjektKriterier.totalLeiepris) && (\r\n \r\n )}\r\n \r\n
\r\n );\r\n};\r\n\r\nexport default BefaringSide;\r\n","import cn from 'classnames';\r\nimport React, { PropsWithChildren } from 'react';\r\n\r\ninterface IHeading {\r\n styles?: string;\r\n}\r\n\r\nexport default function Heading({ children, styles }: PropsWithChildren) {\r\n return children ? {children}
: null;\r\n}\r\n\r\nexport const styles = {\r\n largeHead : \"-large\"\r\n}\r\n","import React, { ReactNode, FC, useState } from 'react';\r\nimport cn from 'classnames';\r\nimport './Accordion.scss';\r\n\r\nimport IconReactIcons, { IconTypes } from 'components/Icon/IconReactIcons';\r\n\r\nexport interface AccordionProps {\r\n title: string;\r\n children: ReactNode;\r\n defaultOpen?: boolean;\r\n borders?: boolean;\r\n}\r\n\r\nconst Accordion: FC = ({ title, children, defaultOpen = false, borders = false }) => {\r\n const [open, setOpen] = useState(defaultOpen);\r\n\r\n return (\r\n \r\n
\r\n {open &&
{children}
}\r\n
\r\n );\r\n};\r\n\r\nexport default Accordion;\r\n","import React from 'react';\r\nimport classnames from 'classnames';\r\nimport styles from './Checkbox.module.css';\r\nimport IconReactIcons, { IconTypes } from '../Icon/IconReactIcons';\r\n\r\ntype CheckboxProps = {\r\n label: string;\r\n className?: string;\r\n inverted?: boolean;\r\n checked?: boolean;\r\n name?: string;\r\n};\r\n\r\nconst Checkbox = ({\r\n label,\r\n className,\r\n inverted,\r\n name,\r\n checked,\r\n ...props\r\n}: CheckboxProps) => {\r\n const id = `${label.replace(/ /g, '_')}-checkbox`;\r\n return (\r\n \r\n );\r\n};\r\n\r\nexport default Checkbox;\r\n","// extracted by mini-css-extract-plugin\nexport default {\"label\":\"Checkbox-module__label__Jn-iD\",\"fakeBox\":\"Checkbox-module__fakeBox__RX4C3\",\"inverted\":\"Checkbox-module__inverted__obS8s\",\"input\":\"Checkbox-module__input__vzLcO\"};","import React, { InputHTMLAttributes, ChangeEvent, DragEvent } from 'react';\r\n\r\nimport './AdvancedFileSelector.scss';\r\n\r\nimport IconReactIcons, { IconTypes } from 'components/Icon/IconReactIcons';\r\nimport cn from 'classnames';\r\n\r\nexport const acceptedFileTypes = {\r\n AllTypes: '.pdf, .docx, .xls, .xlsx, .png, .jpg,',\r\n DocAndPdf: '.docx, .pdf'\r\n};\r\n\r\nexport interface AdvancedFileSelectorProps extends InputHTMLAttributes {\r\n name: string;\r\n label?: string;\r\n highlightLabel?: string;\r\n instruction?: string;\r\n invalid?: boolean;\r\n autoUpload?: boolean;\r\n onChange: (e: ChangeEvent) => void;\r\n}\r\n\r\nconst AdvancedFileSelector = ({\r\n name,\r\n label,\r\n highlightLabel,\r\n instruction,\r\n onChange,\r\n invalid,\r\n autoUpload,\r\n ...rest\r\n}: AdvancedFileSelectorProps) => {\r\n const dropHandler = (event: DragEvent) => {\r\n // Prevent default behavior (Prevent file from being opened)\r\n event.preventDefault();\r\n\r\n if (event.dataTransfer.files && event.dataTransfer.files.length > 0) {\r\n let convertedEvent = event as unknown as ChangeEvent;\r\n convertedEvent.target.files = event.dataTransfer.files;\r\n onChange(convertedEvent);\r\n } else {\r\n console.log('error!');\r\n }\r\n };\r\n\r\n return (\r\n \r\n );\r\n};\r\n\r\nexport default AdvancedFileSelector;\r\n","import React, { useEffect, useState } from 'react';\r\n\r\nimport './FileListWithSort.scss';\r\n\r\nimport IconReactIcons, { IconTypes } from 'components/Icon/IconReactIcons';\r\nimport { Fildata } from 'types/Fildata';\r\nimport { shortDateTimeString } from 'js/date-helper';\r\n\r\ninterface FileListWithSortProps {\r\n files: Fildata[];\r\n onRemove: (id: string) => void;\r\n readOnly: boolean;\r\n interactionDisabled: boolean;\r\n}\r\n\r\nenum sortOptions {\r\n dateAscending = 'dateAsc',\r\n dateDescending = 'dateDesc',\r\n documentAscending = 'documentAsc',\r\n documentDescending = 'documentDesc'\r\n}\r\n\r\nconst FilelistWithSort = ({ files, onRemove, readOnly, interactionDisabled }: FileListWithSortProps) => {\r\n const [sortOption, setSortOption] = useState('');\r\n const [orderedFiles, setOrderedFiles] = useState(files);\r\n\r\n const dateSort = (a: Fildata, b: Fildata) => {\r\n const dateA = new Date(a.opplastetDato ?? '');\r\n const dateB = new Date(b.opplastetDato ?? '');\r\n\r\n if (sortOption == sortOptions.dateDescending) {\r\n return dateA > dateB ? 1 : -1;\r\n } else if (sortOption == sortOptions.dateAscending) {\r\n return dateB > dateA ? 1 : -1;\r\n }\r\n return 0;\r\n };\r\n\r\n useEffect(() => {\r\n setOrderedFiles((prevState) => files);\r\n }, [files]);\r\n\r\n useEffect(() => {\r\n switch (sortOption) {\r\n case sortOptions.dateAscending:\r\n setOrderedFiles([...orderedFiles.sort(dateSort)]);\r\n break;\r\n case sortOptions.dateDescending:\r\n setOrderedFiles([...orderedFiles.sort(dateSort)]);\r\n break;\r\n case sortOptions.documentAscending:\r\n setOrderedFiles([\r\n ...orderedFiles.sort((a, b) => {\r\n return ('' + a.visningsnavn).localeCompare(b.visningsnavn);\r\n })\r\n ]);\r\n break;\r\n case sortOptions.documentDescending:\r\n setOrderedFiles([\r\n ...orderedFiles.sort((a, b) => {\r\n return ('' + b.visningsnavn).localeCompare(a.visningsnavn);\r\n })\r\n ]);\r\n break;\r\n }\r\n }, [sortOption]);\r\n\r\n return (\r\n \r\n
\r\n
\r\n \r\n
\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n );\r\n};\r\n\r\nconst SortOptionLabel = ({ title, activeOption, conditionLabels }) => {\r\n const optionA = conditionLabels[0];\r\n const optionB = conditionLabels[1];\r\n\r\n return (\r\n <>\r\n {title}\r\n {activeOption === optionB && }\r\n {activeOption === optionA && }\r\n {activeOption !== optionB && activeOption !== optionA && }\r\n >\r\n );\r\n};\r\n\r\nexport default FilelistWithSort;\r\n","import ErrorMessage, { IErrorMessage } from 'components/ErrorMessage/ErrorMessage';\r\nimport React from 'react';\r\n\r\nexport interface ErrorProps {\r\n msg: string;\r\n targetKey?: string;\r\n percentageTopPos?: number;\r\n percentageRightPos?: number;\r\n}\r\n\r\nconst AnchoredErrorMessage = (props: ErrorProps) => {\r\n return (\r\n \r\n \r\n
\r\n );\r\n};\r\n\r\nexport default AnchoredErrorMessage;\r\n","import ErrorMessage, { IErrorMessage } from 'components/ErrorMessage/ErrorMessage';\r\nimport Icon from 'components/Icon/Icon';\r\nimport React, { FC } from 'react';\r\nimport AnchoredErrorMessage, { ErrorProps } from '../AnchoredErrorMessage/AnchoredErrorMessage';\r\n\r\nexport interface FormSubmitBoxProps {\r\n heading: string;\r\n bodyText?: string;\r\n disabled: boolean;\r\n buttonText: string;\r\n regretButtonText?: string;\r\n submitUrl?: string;\r\n submitFunc: (url: string) => void;\r\n regretFunc?: (url: string) => void;\r\n dokumenterPublisert?: boolean;\r\n error?: ErrorProps;\r\n\r\n children?: React.ReactNode;\r\n}\r\n\r\nconst FormSubmitBox: FC = ({\r\n heading,\r\n bodyText,\r\n disabled,\r\n buttonText,\r\n regretButtonText,\r\n submitUrl,\r\n submitFunc,\r\n regretFunc,\r\n dokumenterPublisert,\r\n error,\r\n children\r\n}) => {\r\n return (\r\n \r\n
{heading}
\r\n {children &&
{children}
}\r\n
\r\n {bodyText &&
{bodyText}
}\r\n {dokumenterPublisert && regretFunc ? (\r\n
\r\n ) : (\r\n
\r\n )}\r\n {error &&
}\r\n
\r\n
\r\n );\r\n};\r\n\r\nexport default FormSubmitBox;\r\n","import React, { FC, ReactNode, useEffect, useMemo } from 'react';\r\nimport './Modal.scss';\r\nimport IconReactIcons, { IconTypes } from 'components/Icon/IconReactIcons';\r\nimport { createPortal } from 'react-dom';\r\n\r\nexport type ModalProps = {\r\n title?: string;\r\n open: boolean;\r\n children: ReactNode;\r\n onClose: () => void;\r\n clickOutsideToClose?: boolean;\r\n showQuitButton?: boolean;\r\n};\r\n\r\nconst Modal = ({ title, open, children, onClose, clickOutsideToClose = false, showQuitButton = true }: ModalProps) => {\r\n function handleClick({ target }: React.MouseEvent) {\r\n if (clickOutsideToClose && target instanceof HTMLElement && !target.closest('.modal__inner')) {\r\n onClose();\r\n }\r\n }\r\n\r\n return open ? (\r\n \r\n \r\n
\r\n {showQuitButton && (\r\n
\r\n )}\r\n {title &&
{title}
}\r\n {children}\r\n
\r\n
\r\n \r\n ) : (\r\n <>>\r\n );\r\n};\r\n\r\nconst Portal: FC = ({ children }) => {\r\n const el = useMemo(() => document.createElement('div'), []);\r\n\r\n useEffect(() => {\r\n document.body.appendChild(el);\r\n document.body.style.overflow = 'hidden';\r\n return () => {\r\n document.body.removeChild(el);\r\n document.body.style.overflow = 'auto';\r\n };\r\n }, []);\r\n\r\n return createPortal(children, el);\r\n};\r\n\r\nexport default Modal;\r\n","import classnames from 'classnames';\r\nimport IconReactIcons, { IconTypes } from 'components/Icon/IconReactIcons';\r\nimport { recommendationFlagsToEnumValue } from 'js/SortLeieObjekter';\r\nimport React from 'react';\r\nimport { ObjektVurdering } from 'types/ObjektVurdering';\r\n\r\ninterface ReccomendationLabel {\r\n anbefalingsEnum: SeriositetsLabels | BefaringLabels;\r\n vurdering: ObjektVurdering;\r\n}\r\n\r\nexport enum SeriositetsLabels {\r\n 'Ikke vurdert' = -1,\r\n 'Anbefales' = 0,\r\n 'Anbefales med anmerkninger' = 1,\r\n 'Anbefales ikke' = 2,\r\n 'TRUKKET' = 3\r\n}\r\n\r\nexport enum BefaringLabels {\r\n 'Ikke vurdert' = -1,\r\n 'Anbefales å vurdere for deltakelse i konkurransen' = 0,\r\n 'Anbefalt av Oppdragsgiver' = 1,\r\n 'Anbefales å utelukke fra konkurransen' = 2,\r\n 'TRUKKET' = 3\r\n}\r\n\r\nconst ReccomendationLabel = ({ anbefalingsEnum, vurdering }) => {\r\n const value = recommendationFlagsToEnumValue(\r\n true,\r\n vurdering.erAnbefalt,\r\n vurdering.erAnbefaltMedAnmerkninger,\r\n vurdering.erTrukket\r\n );\r\n\r\n const classes = classnames('reccomendation-label', {\r\n '-green': value === 0,\r\n '-yellow': value === 1,\r\n '-red': value === 2 || value === 3\r\n });\r\n\r\n const renderIcon = (value) => {\r\n return (\r\n \r\n {value === 0 || value == 3 ? (\r\n false\r\n ) : value === 1 ? (\r\n \r\n ) : (\r\n \r\n )}\r\n \r\n );\r\n };\r\n\r\n return (\r\n \r\n {renderIcon(value)}\r\n {anbefalingsEnum[value]}\r\n \r\n );\r\n};\r\n\r\nexport default ReccomendationLabel;\r\n","enum RapportVisning {\r\n redigerRapportView,\r\n levertRapportView,\r\n lesRapportView,\r\n godkjentRapportView\r\n}\r\n\r\nexport default RapportVisning;\r\n","import React, { FC, useState, ChangeEvent } from 'react';\r\nimport { cleanPost, post, upload } from 'js/api-helper';\r\nimport Heading from '../../components/Heading/Heading';\r\nimport Accordion from 'components/Accordion/Accordion';\r\nimport Input from '../../components/Input/Input';\r\nimport Checkbox from 'components/Checkbox/Checkbox';\r\nimport IconReactIcons, { IconTypes } from 'components/Icon/IconReactIcons';\r\nimport PageLinkMenu from 'components/PageLinkMenu/PageLinkMenu';\r\nimport { LinkItem } from 'types/LinkItem';\r\nimport AdvancedFileSelector, { acceptedFileTypes } from 'components/AdvancedFileSelector/AdvancedFileSelector';\r\nimport FilelistWithSort from 'components/FileListWithSort/FileListWithSort';\r\nimport { Fildata } from 'types/Fildata';\r\nimport FormSubmitBox from 'components/FormSubmitBox/FormSubmitBox';\r\nimport Modal from 'components/Modal/Modal';\r\nimport ReccomendationLabel, { BefaringLabels } from 'components/ReccomendationLabel/ReccomendationLabel';\r\nimport { ObjektVurdering } from 'types/ObjektVurdering';\r\nimport AnchoredErrorMessage, { ErrorProps } from 'components/AnchoredErrorMessage/AnchoredErrorMessage';\r\nimport RapportVisning from 'types/no-gen/RapportVisning';\r\n\r\nexport interface BefaringsRapportSide {\r\n title: string;\r\n summary: { title: string; text: string; anbefaling: ObjektVurdering }[];\r\n befaringFullfort: boolean;\r\n\r\n visning: number;\r\n lastOppVedleggUrl: string;\r\n slettVedleggUrl: string;\r\n\r\n pageLinks?: LinkItem[];\r\n sendAnbefalingerUrl?: string; // url hvor PL kan sende anbefaling\r\n vedlegg?: Fildata[]; //gjelder bare evt. vedlegg PL laster opp\r\n\r\n anbefalingerGodkjentKommentar?: string; //evt. kommentarer OG har gitt\r\n anbefalingerGodkjennUrl?: string;\r\n anbefalingerGodkjentDato?: string; //dato for godkjennelse fra OG\r\n}\r\n\r\nconst BefaringsRapportSide: FC = ({\r\n title,\r\n pageLinks,\r\n summary,\r\n\r\n befaringFullfort,\r\n sendAnbefalingerUrl,\r\n vedlegg,\r\n lastOppVedleggUrl,\r\n slettVedleggUrl,\r\n\r\n anbefalingerGodkjentKommentar,\r\n anbefalingerGodkjennUrl,\r\n anbefalingerGodkjentDato,\r\n visning\r\n}) => {\r\n const [formdata, setFormdata] = useState({\r\n anbefalingerGodkjentKommentar: anbefalingerGodkjentKommentar ?? '',\r\n betingelserGodtatt: visning == RapportVisning.godkjentRapportView ?? false,\r\n vedlegg: vedlegg ?? []\r\n });\r\n\r\n const [view, setView] = useState(visning);\r\n\r\n const [modal, setModal] = useState(false);\r\n const [error, setError] = useState();\r\n\r\n const reloadPage = () => {\r\n window.location.reload();\r\n };\r\n\r\n const submitReccomendations = async (url) => {\r\n try {\r\n await post(url, { anbefalingerSendt: true });\r\n reloadPage();\r\n } catch (error) {\r\n console.log('error!');\r\n }\r\n };\r\n\r\n const approveWithComments = async (url) => {\r\n //post submit, submit relevant comments if any\r\n try {\r\n await post(url, { kommentar: formdata.anbefalingerGodkjentKommentar });\r\n reloadPage();\r\n } catch (error) {\r\n console.log('error!');\r\n }\r\n };\r\n\r\n const submitAttachments = async (e: ChangeEvent) => {\r\n const fileList = Array.from(e.target.files ?? []);\r\n const data = new FormData();\r\n\r\n try {\r\n for (const file of fileList) {\r\n data.append('file', file);\r\n }\r\n\r\n const res = await cleanPost(lastOppVedleggUrl, data);\r\n\r\n if (res) {\r\n const newList = formdata?.vedlegg;\r\n newList.push(res);\r\n\r\n setFormdata({\r\n ...formdata,\r\n vedlegg: newList\r\n });\r\n }\r\n } catch (error) {\r\n setError({\r\n msg: error.message\r\n });\r\n }\r\n };\r\n\r\n const handleRemoveAttachment = async (id: string) => {\r\n try {\r\n const res = await post(`${slettVedleggUrl}?filId=${id}`);\r\n\r\n setFormdata({\r\n ...formdata,\r\n vedlegg: formdata?.vedlegg?.filter((item) => item.id !== id)\r\n });\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n };\r\n\r\n return (\r\n \r\n
{title}\r\n {pageLinks && pageLinks?.length > 0 &&
}\r\n
0} borders={true}>\r\n \r\n {summary &&\r\n befaringFullfort &&\r\n summary.map((item) => {\r\n return (\r\n
\r\n
\r\n
{item.title}
\r\n \r\n \r\n
{item.text}
\r\n
\r\n );\r\n })}\r\n
\r\n \r\n {/* {!anbefalingerSendt && !anbefalingerGodkjent && allowEditRoles.includes(rolle) && ( */}\r\n {view === RapportVisning.redigerRapportView && (\r\n <>\r\n
\r\n {error?.msg &&
}\r\n
Vedlagte filer
\r\n
{\r\n submitAttachments(e);\r\n }}\r\n accept={acceptedFileTypes.DocAndPdf}\r\n instruction=\"Tillate filtyper er .PDF og .DOCX,\"\r\n >\r\n\r\n {formdata?.vedlegg.length > 0 && (\r\n
{\r\n handleRemoveAttachment(id);\r\n }}\r\n />\r\n )}\r\n \r\n
{\r\n submitReccomendations(url);\r\n setModal(true);\r\n }}\r\n />\r\n setModal(false)}\r\n >\r\n Oppdragsgiver må nå godkjenne befaringsrapporten for å gå videre til seriøsitetssjekk.
\r\n \r\n >\r\n )}\r\n {/* {anbefalingerSendt && !anbefalingerGodkjent && allowEditRoles.includes(rolle) && ( */}\r\n {view === RapportVisning.levertRapportView && (\r\n <>\r\n \r\n
Vedlagte filer
\r\n {\r\n handleRemoveAttachment(id);\r\n }}\r\n >\r\n \r\n \r\n
\r\n
Anbefalinger har blitt levert til oppdragsgiver
\r\n
Prosessen avventer nå godkjenning.
\r\n
\r\n
\r\n >\r\n )}\r\n {/* {anbefalingerSendt && !anbefalingerGodkjent && rolle == 'OG' && ( */}\r\n {view == RapportVisning.lesRapportView && (\r\n <>\r\n \r\n
Vedlagte filer
\r\n {\r\n handleRemoveAttachment(id);\r\n }}\r\n >\r\n \r\n \r\n
\r\n
\r\n
Oppdragsgivers vurdering
\r\n \r\n
\r\n
\r\n {\r\n setFormdata({\r\n ...formdata,\r\n [e.currentTarget.name]: e.currentTarget.value\r\n });\r\n }}\r\n name=\"anbefalingerGodkjentKommentar\"\r\n type=\"textarea\"\r\n >\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
Oppdragsgivers godkjenning
\r\n \r\n
\r\n {\r\n setFormdata({\r\n ...formdata,\r\n betingelserGodtatt: e.currentTarget.checked\r\n });\r\n }}\r\n >\r\n
\r\n
\r\n
{\r\n approveWithComments(url);\r\n setModal(true);\r\n }}\r\n />\r\n setModal(false)}>\r\n Befaringsrapporten er nå godkjent og søket vil gå videre til seriøsitetssjekk.
\r\n \r\n \r\n >\r\n )}\r\n {view == RapportVisning.godkjentRapportView && (\r\n <>\r\n \r\n
Vedlagte filer
\r\n {\r\n handleRemoveAttachment(id);\r\n }}\r\n >\r\n \r\n {anbefalingerGodkjentKommentar && (\r\n \r\n
\r\n
Oppdragsgivers kommentar
\r\n \r\n\r\n
\r\n
{anbefalingerGodkjentKommentar}
\r\n
\r\n
\r\n )}\r\n {anbefalingerGodkjentDato && (\r\n \r\n
\r\n
Oppdragsgivers godkjenning
\r\n \r\n
\r\n
{anbefalingerGodkjentDato}
\r\n
\r\n
\r\n )}\r\n >\r\n )}\r\n \r\n );\r\n};\r\n\r\nexport default BefaringsRapportSide;\r\n","import SelectField, { Choice } from 'components/SelectField/SelectField';\r\nimport { useDebounce, useOnChange } from 'js/hooks';\r\nimport React, { useCallback, useState } from 'react';\r\nimport { components } from 'react-select';\r\nimport IconReactIcons, { IconTypes } from 'components/Icon/IconReactIcons';\r\n\r\nexport interface Props {\r\n readonly label?: string;\r\n readonly initialValue?: string;\r\n readonly onChange?: (value: string, label: string) => void;\r\n readonly onSearch: (value: string) => Promise[]>;\r\n readonly validationState?: null | 'error' | 'loading';\r\n readonly feedback?: string;\r\n readonly feedbackMargin?: boolean;\r\n readonly placeholder?: string;\r\n readonly formatOptionLabel?: (opt, context) => string;\r\n readonly disabled?: boolean;\r\n}\r\n\r\nconst DropdownIndicator = (props: object) => {\r\n return (\r\n \r\n \r\n \r\n );\r\n};\r\n\r\nexport default function AutoCompleteField({\r\n label,\r\n initialValue,\r\n onChange = () => {},\r\n onSearch,\r\n validationState,\r\n feedback,\r\n feedbackMargin,\r\n formatOptionLabel,\r\n disabled,\r\n placeholder\r\n}: Props) {\r\n const [value, setValue] = useState(initialValue);\r\n const [loading, setLoading] = useState(false);\r\n const [choices, setChoices] = useState[]>([]);\r\n const [searchInput, setSearchInput] = useState('');\r\n\r\n const debouncedSearchInput = useDebounce(searchInput, 500);\r\n\r\n const search = useCallback(async (value: string) => {\r\n if (!value) return;\r\n setLoading(true);\r\n setChoices([]);\r\n const result = await onSearch(value);\r\n setLoading(false);\r\n setChoices(result);\r\n }, []);\r\n\r\n useOnChange(search, [debouncedSearchInput]);\r\n\r\n return (\r\n (loading ? 'Laster' : 'Fant ikke noe på søk')}\r\n onInputChange={setSearchInput}\r\n onChange={(e) => {\r\n setValue(e.label);\r\n onChange(e.value, e.label);\r\n }}\r\n validationState={validationState}\r\n feedback={feedback}\r\n feedbackMargin={feedbackMargin}\r\n components={{ DropdownIndicator }}\r\n placeholder={placeholder}\r\n formatOptionLabel={formatOptionLabel}\r\n />\r\n );\r\n}\r\n","import cn from 'classnames';\r\nimport AutoCompleteField, {\r\n Props as AutoCompleteFieldProps\r\n} from 'components/AutoCompleteField/AutoCompleteField';\r\nimport * as api from 'js/api-helper';\r\nimport React from 'react';\r\n\r\ninterface Response {\r\n readonly organisasjonResponse: {\r\n readonly organisasjonsnummer: string;\r\n readonly navn: string;\r\n }[];\r\n\r\n readonly status: string;\r\n}\r\n\r\nasync function handleSearch(value: string) {\r\n if (!value || value.length < 3) return [];\r\n\r\n try {\r\n const response: Response = await api.get(\r\n `/api/v1/data/OrganisasjonsvelgerSok/${value}`\r\n );\r\n\r\n if (!response.organisasjonResponse) return [];\r\n\r\n return response.organisasjonResponse.map((e) => ({\r\n label: e.navn,\r\n value: e.organisasjonsnummer\r\n }));\r\n } catch (e) {\r\n return [];\r\n }\r\n}\r\n\r\nexport type Props = Omit;\r\n\r\nexport default function Organisasjonsvelger(props: Props) {\r\n\r\n return (\r\n \r\n );\r\n}\r\n","import { upload, ValidationError } from 'js/api-helper';\r\nimport React, { useCallback, useState } from 'react';\r\nimport { IconTypes, getIcon } from 'components/Icon/IconReactIcons';\r\n\r\nconst acceptedFileTypes = {\r\n document: '.pdf, .docx',\r\n documentAndImages: '.pdf, .docx, .png, .jpg, .jpeg',\r\n image: '.png, .jpg, .jpeg'\r\n};\r\n\r\nexport type AcceptedFileTypes = keyof typeof acceptedFileTypes;\r\n\r\nexport interface File {\r\n readonly id: string;\r\n readonly nedlastingslenke: string;\r\n readonly visningsnavn: string;\r\n}\r\n\r\nexport interface Props {\r\n readonly fileType: keyof typeof acceptedFileTypes;\r\n readonly destinationUrl: string;\r\n readonly onUploadComplete?: (file: File) => void;\r\n readonly multiple?: boolean;\r\n readonly styles?: string;\r\n}\r\n\r\nexport function fileTypes(fileType: AcceptedFileTypes): string {\r\n return acceptedFileTypes[fileType];\r\n}\r\n\r\nexport const Styles = {\r\n ButtonAsLink: 'buttonAsLink'\r\n};\r\n\r\nexport default function UploadButton({ fileType, destinationUrl, onUploadComplete, multiple = false, styles }: Props) {\r\n const [isBusy, setBusy] = useState(false);\r\n const [uploadFailedMessage, setUploadFailedMessage] = useState();\r\n\r\n const handleUpload = useCallback(\r\n async (files: globalThis.File[]) => {\r\n setBusy(true);\r\n setUploadFailedMessage(undefined);\r\n try {\r\n for (const file of files) {\r\n const data = new FormData();\r\n data.append('file', file);\r\n try {\r\n const result = await upload(destinationUrl, data);\r\n onUploadComplete?.(result);\r\n } catch (error) {\r\n if (error instanceof ValidationError) {\r\n setUploadFailedMessage(error['file']);\r\n return;\r\n }\r\n }\r\n }\r\n } finally {\r\n // There is a warning in the devtools because of this line; ignore it.\r\n // If this component is unmounted because of the onUploadComplete call above,\r\n // then it's too late to update the state here. It warns that it's a memory leak,\r\n // but it's not really, so nothing to worry about.\r\n setBusy(false);\r\n }\r\n },\r\n [destinationUrl, onUploadComplete]\r\n );\r\n if (styles !== Styles.ButtonAsLink) {\r\n return (\r\n \r\n );\r\n } else {\r\n return (\r\n \r\n );\r\n }\r\n}\r\n","import { post } from 'js/api-helper';\r\nimport React, { useCallback, useState } from 'react';\r\nimport IconReactIcons, { IconTypes, getIcon } from 'components/Icon/IconReactIcons';\r\n\r\nexport interface Props {\r\n readonly slettUrl: string;\r\n onDelete(res: Record): void;\r\n}\r\n\r\nexport default function DeleteButton({ slettUrl, onDelete }: Props) {\r\n const [isBusy, setBusy] = useState(false);\r\n const [deleteFailedMessage, setdeleteFailedMessage] = useState();\r\n\r\n const deleteEntry = useCallback(async () => {\r\n if (!slettUrl) return;\r\n setBusy(true);\r\n try {\r\n const result = await post(slettUrl);\r\n onDelete(result);\r\n } catch (error) {\r\n setdeleteFailedMessage('Ooops! vi klarte ikke slette bildet.
Vennligst prøv igjen senere.');\r\n return;\r\n } finally {\r\n setBusy(false);\r\n }\r\n }, []);\r\n\r\n return (\r\n \r\n );\r\n}\r\n","import UploadButton, { Styles } from 'components/UploadButton/UploadButton';\r\nimport React, { useCallback, useState } from 'react';\r\nimport Paragraph from 'components/Paragraph/Paragraph';\r\nimport DeleteButton from 'components/DeleteButton/DeleteButton';\r\n\r\nexport interface Props {\r\n readonly url: string;\r\n readonly uploadUrl: string;\r\n readonly deleteUrl?: string;\r\n}\r\n\r\nexport default function ProfilBildePanel(props: Props) {\r\n const [url, setUrl] = useState(props.url);\r\n\r\n const onDelete = useCallback((res) => {\r\n setUrl('');\r\n }, []);\r\n\r\n return (\r\n \r\n
\r\n
Legg til et profilbilde:
\r\n
\r\n Profilbildet brukes i hovedsak sammen med et innsendt svar, bildet er ellers unntatt offentligheten.\r\n \r\n\r\n
\r\n
\r\n\r\n {url ? (\r\n

\r\n ) : (\r\n
setUrl(file.nedlastingslenke)}\r\n />\r\n )}\r\n \r\n );\r\n}\r\n","import Heading from 'components/Heading/Heading';\r\nimport Organisasjonsvelger from 'components/Organisasjonsvelger/Organisasjonsvelger';\r\nimport ProfilBildePanel from 'components/ProfilBildePanel/ProfilBildePanel';\r\nimport SelectField from 'components/SelectField/SelectField';\r\nimport * as api from 'js/api-helper';\r\nimport { dateTimeString } from 'js/date-helper';\r\nimport { usePostback } from 'js/hooks';\r\nimport React, { FC, useCallback, useState } from 'react';\r\nimport { AiOutlineSync } from 'react-icons/ai';\r\nimport Button from 'components/Button/Button';\r\nimport Field from 'components/Field/Field';\r\nimport Modal from 'components/Modal/Modal';\r\nimport type { LinkItemChild } from 'types/LinkItemChild';\r\n\r\n// This is here to make the c# generator pick up LinkItemChild\r\nconst x: LinkItemChild = {\r\n url: '',\r\n text: ''\r\n};\r\n\r\nexport interface BrukerSide {\r\n readonly id: string;\r\n readonly fulltNavn: string;\r\n readonly oppgittOrganisasjon: string;\r\n readonly organisasjonsnavn: string;\r\n readonly organisasjonsnummer: string;\r\n readonly epostRedigerbar: boolean;\r\n readonly epost: string;\r\n readonly telefonRedigerbar: boolean;\r\n readonly telefon: string;\r\n readonly rolle: string;\r\n readonly rollenavn: string;\r\n readonly sistInnloggetUtc: string;\r\n readonly antallInnlogginger: number;\r\n readonly rollevalg: {\r\n readonly rolle: string;\r\n readonly rollenavn: string;\r\n }[];\r\n readonly slettBrukerBekreftTekst: string;\r\n readonly redigerBrukerApiUrl: string;\r\n readonly slettBrukerApiUrl: string;\r\n readonly lagreProfilBildeUrl: string;\r\n readonly profilBildeUrl: string;\r\n readonly slettProfilBildeUrl: string;\r\n}\r\n\r\nconst BrukerSide: FC = (props) => {\r\n const [isPopupOpen, setPopupOpen] = useState(false);\r\n\r\n const [rolle, setRolle] = useState(props.rolle);\r\n const [epost, setEpost] = useState(props.epost);\r\n const [telefon, setTelefon] = useState(props.telefon);\r\n const [organisasjonsnummer, setOrganisasjonsnummer] = useState(props.organisasjonsnummer);\r\n\r\n const rolleListe = props.rollevalg.map((r) => ({\r\n label: r.rollenavn,\r\n value: r.rolle\r\n }));\r\n const rolleSelected = rolleListe.find((r) => r.value === rolle);\r\n\r\n const { postback, validation, canSubmit, isBusy } = usePostback(props.redigerBrukerApiUrl, {\r\n rolle,\r\n epost,\r\n telefon,\r\n organisasjonsnummer\r\n });\r\n\r\n const lagreBruker = useCallback(async () => {\r\n await postback();\r\n window.location.href = '/admin/rollerbrukere';\r\n }, [postback]);\r\n\r\n const hidePopup = useCallback(() => setPopupOpen(false), []);\r\n const showPopup = useCallback(() => setPopupOpen(true), []);\r\n\r\n const slettBruker = useCallback(async () => {\r\n await api.post(props.slettBrukerApiUrl);\r\n window.location.href = '/admin/rollerbrukere';\r\n }, [props.slettBrukerApiUrl]);\r\n\r\n return (\r\n <>\r\n Rediger bruker\r\n \r\n
\r\n
\r\n
Navn
\r\n\r\n
{props.fulltNavn}
\r\n\r\n {props.oppgittOrganisasjon &&
Organisasjon oppgitt av brukeren
}\r\n {props.oppgittOrganisasjon &&
{props.oppgittOrganisasjon}
}\r\n\r\n
Departement / Virksomhet
\r\n
setOrganisasjonsnummer(orgNummer)}\r\n {...validation.organisasjonsnummer}\r\n />\r\n\r\n Epost
\r\n {props.epostRedigerbar ? (\r\n setEpost(e.target.value)}\r\n {...validation.epost}\r\n />\r\n ) : (\r\n {props.epost}
\r\n )}\r\n\r\n Telefon
\r\n {props.telefonRedigerbar ? (\r\n setTelefon(e.target.value)}\r\n name=\"Telefon\"\r\n label=\"\"\r\n defaultValue={props.telefon}\r\n {...validation.telefon}\r\n />\r\n ) : (\r\n {props.telefon}
\r\n )}\r\n\r\n Rolle
\r\n setRolle(selected.value)}\r\n {...validation.rolle}\r\n />\r\n\r\n \r\n {props.slettBrukerBekreftTekst.split('\\n').map((line, key) => (\r\n {line}
\r\n ))}\r\n \r\n \r\n \r\n
\r\n \r\n \r\n\r\n
\r\n
\r\n {isBusy &&
}\r\n\r\n
\r\n\r\n
\r\n
\r\n
\r\n \r\n
\r\n
Sist innlogget:
\r\n
{dateTimeString(props.sistInnloggetUtc)}
\r\n
\r\n
\r\n
Antall innlogginger:
\r\n
{props.antallInnlogginger}
\r\n
\r\n
\r\n >\r\n );\r\n};\r\n\r\nexport default BrukerSide;\r\n","import React, { FC } from 'react';\r\n\r\nexport interface FeilSide {\r\n readonly feilkode: number;\r\n readonly overskrift: string;\r\n readonly feilmelding: string;\r\n}\r\n\r\nconst FeilSide: FC = (props) => {\r\n return (\r\n \r\n
{props.overskrift}
\r\n
Feilkode: {props.feilkode}
\r\n
{props.feilmelding}
\r\n
\r\n Gå tilbake til forsiden\r\n
\r\n
\r\n );\r\n};\r\n\r\nexport default FeilSide;\r\n","import type { LinkItem } from 'types/LinkItem';\r\nimport React, { FC, useState } from 'react';\r\n\r\nimport PageLinkMenu from 'components/PageLinkMenu/PageLinkMenu';\r\nimport Heading from 'components/Heading/Heading';\r\nimport { IconTypes } from 'components/Icon/IconReactIcons';\r\nimport IconButton from 'components/IconButton/IconButton';\r\nimport { shortDateString } from 'js/date-helper';\r\nimport { TilbudtObjekt } from 'types/TilbudtObjekt';\r\nimport { TilbudtObjektListe } from 'types/TilbudtObjektListe';\r\nimport { SortLeieObjekter } from 'js/SortLeieObjekter';\r\nimport TilbudtObjektCardList, { TilbudtObjektCardListHeadings } from 'components/TilbudtObjektCardList/TilbudtObjektCardList';\r\n\r\nexport interface ForhandlingerInnkomneSide {\r\n readonly title: string;\r\n readonly svarFristUtc: string;\r\n readonly pageLinks: LinkItem[];\r\n readonly arkiverProsjektHref: string;\r\n readonly objekter: TilbudtObjekt[];\r\n}\r\n\r\nconst ForhandlingerInnkomneSide: FC = ({\r\n title,\r\n svarFristUtc,\r\n pageLinks,\r\n arkiverProsjektHref,\r\n objekter\r\n}) => {\r\n const [sortedList, setSortedList] = useState(SortLeieObjekter(objekter));\r\n\r\n const listHeadings: TilbudtObjektCardListHeadings = {\r\n tentative: 'Tentativ liste, mangler godkjenning fra oppdragsgiver',\r\n recommended: 'Anbefales å vurdere disse lokalene for deltakelse i forhandlinger',\r\n notEvaluated: 'Ikke evaluert',\r\n rejected: 'Anbefales å utelukke fra forhandlinger',\r\n canceled: 'Tilbud er trukket'\r\n };\r\n\r\n return (\r\n \r\n
\r\n {title}\r\n \r\n
\r\n
\r\n\r\n
\r\n
\r\n );\r\n};\r\n\r\nexport default ForhandlingerInnkomneSide;\r\n","import React, { useEffect, useState } from 'react';\r\nimport cn from 'classnames';\r\nimport './DynamicFileList.scss';\r\nimport IconReactIcons, { IconTypes } from 'components/Icon/IconReactIcons';\r\nimport { Fildata } from 'types/Fildata';\r\nimport { shortDateTimeString } from 'js/date-helper';\r\nimport { KonkurranseGrunnlagFil } from 'types/KonkurranseGrunnlagFil';\r\nimport {\r\n DropdownMenuTrigger,\r\n DropdownMenu,\r\n DropdownMenuContent,\r\n DropdownMenuItem,\r\n DropdownMenuSeparator\r\n} from 'components/DropdownMenu';\r\nimport { cleanPost } from 'js/api-helper';\r\n\r\ninterface DynamicFileListProps {\r\n files: KonkurranseGrunnlagFil[];\r\n onRemove: (id: string) => void;\r\n onEdit?: (id: string) => void;\r\n readOnly?: boolean;\r\n columns: Array