\n \n );\n};\n\nexport const DeclarationStatusContent = ({\n party,\n declaredParty,\n partyState = CollectionState.noCollection,\n declaration,\n electionType = ElectionType.Folketingsvalg,\n votingRights,\n}: DeclarationStatusProps) => {\n const { pathname } = useRouter();\n const { t } = useDictionary();\n\n let userStatus: UserStatus = getDeclarationStatus(party, declaration);\n\n const {\n daysLeft,\n dateOfInitiation,\n dateOfConfirmation,\n dateOfConfirmationExpiry,\n } = declaration || {};\n\n const electionTypeValue = electionTypeMap[electionType];\n\n if (\n (electionType === ElectionType.Folketingsvalg && !votingRights.dk) ||\n (electionType === ElectionType.EuropaParlamentsvalg && !votingRights.eu)\n ) {\n return (\n \n \n {t('myDeclaration.status_13_13', {\n electionType: t(`${electionTypeValue}Election`),\n asString: true,\n })}\n \n \n );\n }\n\n if (!party || !party.id) {\n return (\n \n );\n }\n\n const interpolation: InterpolationValues = {\n partyName: party.name,\n electionType: t(`${electionTypeValue}Election`),\n daysLeft:\n daysLeft !== undefined\n ? t(daysLeft !== 1 ? 'myDeclaration.days' : 'myDeclaration.days_1', {\n days: daysLeft.toString(),\n })\n : undefined,\n activeParty: declaredParty ? (\n \n {declaredParty?.name}\n \n ) : undefined,\n confirmExpireDate: dateOfConfirmationExpiry ? (\n \n ) : null,\n };\n\n switch (partyState) {\n case CollectionState.running:\n switch (userStatus) {\n case UserStatus.notYetInitiated:\n return (\n \n );\n case UserStatus.initiated:\n return (\n <>\n \n \n \n \n \n >\n );\n case UserStatus.readyToConfirm:\n return (\n <>\n \n \n \n \n \n >\n );\n case UserStatus.confirmed:\n return (\n <>\n \n \n \n >\n );\n case UserStatus.activitiesWithAnotherParty:\n return (\n \n );\n }\n break;\n case CollectionState.locked:\n switch (userStatus) {\n case UserStatus.notYetInitiated:\n return (\n \n );\n case UserStatus.initiated:\n case UserStatus.readyToConfirm:\n return (\n <>\n \n \n \n \n >\n );\n case UserStatus.confirmed:\n return (\n <>\n \n \n >\n );\n case UserStatus.activitiesWithAnotherParty:\n return (\n \n );\n default:\n break;\n }\n break;\n case CollectionState.approved:\n switch (userStatus) {\n case UserStatus.initiated:\n case UserStatus.readyToConfirm:\n case UserStatus.notYetInitiated:\n return (\n \n );\n case UserStatus.confirmed:\n return (\n <>\n \n \n >\n );\n case UserStatus.activitiesWithAnotherParty:\n return (\n \n );\n }\n break;\n case CollectionState.noCollection:\n switch (userStatus) {\n case UserStatus.initiated:\n case UserStatus.confirmed:\n case UserStatus.readyToConfirm:\n case UserStatus.notYetInitiated:\n return (\n \n );\n case UserStatus.activitiesWithAnotherParty:\n return (\n \n );\n }\n break;\n case CollectionState.deactivated:\n switch (userStatus) {\n case UserStatus.notYetInitiated:\n return (\n \n );\n case UserStatus.initiated:\n case UserStatus.readyToConfirm:\n return (\n <>\n \n \n \n \n >\n );\n case UserStatus.confirmed:\n return (\n <>\n \n \n \n >\n );\n case UserStatus.activitiesWithAnotherParty:\n return (\n \n );\n }\n }\n return null;\n};\n","/*\n GENERATED FILE - DO NOT MODIFY\n Any changes will be overwritten when `yarn svgs` is executed.\n \n Generated from: assets/bekraeftet.svg\n If you need to make changes the attributes, modify the original .svg file.\n \n If you need to modify the file further, consider copying this generated file to a new location,\n or into the component that uses it. If you do this, it might make sense to remove the original .svg file, \n or it could be regenerated the next time SVGs are generated.\n*/\nimport * as React from 'react';\nconst BekraeftetIcon = React.forwardRef(\n (props: React.SVGProps, svgRef: any) => (\n \n ),\n);\nexport default BekraeftetIcon;\n","import React from 'react';\nimport { Heading } from '@charlietango/ui';\nimport { rem } from 'polished';\n\nimport { SchemaFrontendUserDataViewModel } from '../../api/api-schema';\nimport {\n CollectionState,\n ElectionType,\n electionTypeMap,\n} from '../../api/api-types';\nimport { useParty } from '../../api/hooks/useParty';\nimport { useDictionary } from '../../hooks/useDictionary';\nimport { useElectionType, usePartyId } from '../../hooks/useSearchParams';\nimport { TextVariant } from '../../styles/typography';\nimport Logo from '../Logo/Logo';\nimport Placeholder from '../Placeholder/Placeholder';\nimport { DeclarationStatusContent } from './DeclarationStatus';\n\nexport type MyDeclarationProps = {\n user?: SchemaFrontendUserDataViewModel;\n className?: string;\n};\n\n/**\n * Show the users current declaration status\n * */\nfunction MyDeclaration({ user, className }: MyDeclarationProps) {\n const { t } = useDictionary();\n const { partyId } = usePartyId();\n const { electionType, isDefined } = useElectionType();\n\n // Determine the voting rights for the user - Can they actually have a declaration?\n const votingRights = user?.votingRights || {};\n\n // Find out if the user has declared to this party (or another party in the same electionType)\n let currentDeclaration = user?.userDeclarations?.find(\n (item) => item.electionType === electionType,\n );\n\n if (!currentDeclaration && !isDefined && user?.userDeclarations?.length) {\n // We don't need a specific declaration, so choose the active one\n currentDeclaration = user.userDeclarations[0];\n }\n // Fetch the party for the current page, and the declared party - You can only be declared to one party, so we need to know if they are the same.\n const { data: party, status } = useParty(partyId);\n const { data: declaredParty, status: declaredStatus } = useParty(\n currentDeclaration?.partyId,\n );\n\n const currentParty = party || declaredParty;\n\n if (!user || declaredStatus === 'loading' || status === 'loading') {\n return ;\n }\n\n // Find the correct electionType for this view. Prefer the electionType in URL, otherwise go with the election\n const selectedElectionType = isDefined\n ? electionType\n : currentDeclaration?.electionType ?? ElectionType.Folketingsvalg;\n\n // Determine the current party state, and fallback to no collection.\n const { state } = (currentParty &&\n currentParty[electionTypeMap[selectedElectionType]]) ?? {\n state: CollectionState.noCollection,\n };\n\n return (\n \n
\n \n \n {t('myDeclaration.title')}\n \n
\n \n \n );\n}\n\nexport default MyDeclaration;\n","/*\n GENERATED FILE - DO NOT MODIFY\n Any changes will be overwritten when `yarn svgs` is executed.\n \n Generated from: assets/open-new-window.svg\n If you need to make changes the attributes, modify the original .svg file.\n \n If you need to modify the file further, consider copying this generated file to a new location,\n or into the component that uses it. If you do this, it might make sense to remove the original .svg file, \n or it could be regenerated the next time SVGs are generated.\n*/\nimport * as React from 'react';\nconst OpenNewWindowIcon = React.forwardRef(\n (props: React.SVGProps, svgRef: any) => (\n \n ),\n);\nexport default OpenNewWindowIcon;\n","import React from 'react';\nimport { Text } from '@charlietango/ui';\n\nimport { TextVariant } from '../../styles/typography';\n\ntype PartyDetailsType = {\n label: React.ReactNode;\n ariaValue?: string;\n value: React.ReactNode;\n};\nexport const itemStyle = {\n boxShadow: ' inset 0 1px 0 0 #dce1e1',\n display: 'flex',\n justifyContent: 'space-between',\n py: 4,\n};\n\nfunction PartyDetailsItem({ label, value, ariaValue }: PartyDetailsType) {\n return (\n
\n \n {label}\n \n \n {value}\n \n
\n );\n}\nexport default PartyDetailsItem;\n","/*\n GENERATED FILE - DO NOT MODIFY\n Any changes will be overwritten when `yarn svgs` is executed.\n \n Generated from: assets/status.svg\n If you need to make changes the attributes, modify the original .svg file.\n \n If you need to modify the file further, consider copying this generated file to a new location,\n or into the component that uses it. If you do this, it might make sense to remove the original .svg file, \n or it could be regenerated the next time SVGs are generated.\n*/\nimport * as React from 'react';\nconst StatusIcon = React.forwardRef(\n (props: React.SVGProps, svgRef: any) => (\n \n ),\n);\nexport default StatusIcon;\n","import React from 'react';\nimport { Text } from '@charlietango/ui';\n\nimport { CollectionState, collectionStateMap } from '../../api/api-types';\nimport { useDictionary } from '../../hooks/useDictionary';\nimport { useElectionType } from '../../hooks/useSearchParams';\nimport StatusIcon from '../../icons/StatusIcon';\nimport { Colors } from '../../styles/colors';\nimport { TextVariant } from '../../styles/typography';\nimport { itemStyle } from './PartyDetailsItem';\n\ntype Props = {\n status?: CollectionState;\n};\n\nfunction Status({ status }: Props) {\n const { electionTypeValue } = useElectionType();\n const runningState = status === CollectionState.running;\n const { t } = useDictionary();\n if (status === undefined || electionTypeValue === undefined) return null;\n\n return (\n
\n );\n}\n\nexport default Status;\n","import React from 'react';\nimport { Heading, Text } from '@charlietango/ui';\n\nimport {\n SchemaPartyDetails,\n SchemaPartyDetailsResponse,\n} from '../../api/api-schema';\nimport { CollectionState } from '../../api/api-types';\nimport { useDictionary } from '../../hooks/useDictionary';\nimport { useElectionType } from '../../hooks/useSearchParams';\nimport OpenNewWindowIcon from '../../icons/OpenNewWindowIcon';\nimport { Colors } from '../../styles/colors';\nimport { TextVariant } from '../../styles/typography';\nimport { dotFormatDate, thousandsSeparators } from '../../utils/format-utils';\nimport Anchor from '../Anchor/Anchor';\nimport PartyDetailsItem, { itemStyle } from './PartyDetailsItem';\nimport Status from './Status';\n\nexport type PartyDetailsProps = {\n party?: SchemaPartyDetailsResponse;\n className?: string;\n children?: React.ReactNode;\n};\n\nfunction formatUrl(url: string) {\n if (!/^https?:\\/\\//.test(url)) {\n // Ensure we add the protocol to the URL\n return `https://${url}`;\n }\n return url;\n}\n\nfunction PartyDetails({ party, className, children }: PartyDetailsProps) {\n const { electionTypeValue } = useElectionType();\n const { t } = useDictionary();\n\n const currentParty: SchemaPartyDetails =\n party && electionTypeValue ? party[electionTypeValue] : undefined;\n\n if (\n !party ||\n !currentParty ||\n currentParty.state === CollectionState.noCollection\n ) {\n return ;\n }\n\n return (\n
\n {party.name && (\n \n {party.name}\n \n )}\n
\n {party.representative?.name ? (\n /*\n - IF there is only representative, it will be visible in party details as \"Repræsentant\".\n - IF there is only owner, it will be visible in party details as \"Indehaver\".\n - IF there are both representative and owner, only \"Repræsentant\" is visible in party details.\n */\n \n ) : party.owner?.name ? (\n \n ) : null}\n {currentParty.voteCount !== undefined ? (\n \n ) : null}\n\n \n {currentParty.expiryDate ? (\n \n {dotFormatDate(currentParty.expiryDate)}\n \n }\n />\n ) : null}\n {party.contact?.address ? (\n \n {party.contact.address}\n \n }\n />\n ) : null}\n {party.contact?.phone ? (\n \n {party.contact.phone}\n \n }\n />\n ) : null}\n {party.contact?.email ? (\n \n {party.contact.email}\n \n }\n />\n ) : null}\n
\n );\n}\n\nexport default PartyDetails;\n","import React, { useEffect } from 'react';\nimport { hot } from 'react-hot-loader/root';\nimport { Container, Grid, GridItem, Heading, Text } from '@charlietango/ui';\nimport { rem } from 'polished';\n\nimport { CollectionState } from '../../api/api-types';\nimport { useParty } from '../../api/hooks/useParty';\nimport { useUser } from '../../api/hooks/useUser';\nimport DocumentTitle from '../../application/DocumentTitle';\nimport Anchor from '../../components/Anchor/Anchor';\nimport Arrow from '../../components/Arrow/Arrow';\nimport ElectionTypeNavigation from '../../components/ElectionTypeNavigation/ElectionTypeNavigation';\nimport HowToSection from '../../components/HowToSection/HowToSection';\nimport InitiateDeclaration from '../../components/InitiateDeclaration/InitiateDeclaration';\nimport InitiateDeclarationViewModel from '../../components/InitiateDeclaration/types/InitiateDeclarationViewModel';\nimport MyDeclaration from '../../components/MyDeclaration/MyDeclaration';\nimport PartyDetails from '../../components/PartyDetails/PartyDetails';\nimport Placeholder from '../../components/Placeholder/Placeholder';\nimport { useElectionType, usePartyId } from '../../hooks/useSearchParams';\nimport { Colors } from '../../styles/colors';\nimport { TextVariant } from '../../styles/typography';\nimport { motion } from '../../utils/motion';\nimport AccordionViewModel from '../../view-models/AccordionViewModel';\nimport LinkViewModel from '../../view-models/LinkViewModel';\nimport { NotFound } from '../NotFound/NotFound';\nimport NotFoundViewModel from '../NotFound/types/NotFoundViewModel';\nimport { PlausibleGoals, trackEvent } from '../../utils/tracking';\n\nexport type PartyPageProps = {\n /** Intro labels based on what elections a party is applying for */\n introLabels?: {\n dk: string;\n eu: string;\n all: string;\n };\n initiateDeclaration?: InitiateDeclarationViewModel;\n howTo?: AccordionViewModel;\n attentionAnalogue?: LinkViewModel;\n notFound?: NotFoundViewModel;\n};\n\nexport function PartyPage({\n attentionAnalogue,\n introLabels,\n initiateDeclaration,\n notFound,\n howTo,\n}: PartyPageProps) {\n const { user, userReady } = useUser();\n const { partyId } = usePartyId();\n const { electionType, electionTypeValue } = useElectionType();\n const { data: party, error } = useParty(partyId);\n\n useEffect(() => {\n if (party) {\n trackEvent(PlausibleGoals.Party, {\n props: party.name ? { parti: party.name } : {},\n });\n }\n }, [party]);\n\n if (error || (userReady && !partyId)) {\n // If we got an error when fetching the party, or if there isn't a valid partyId\n return ;\n }\n if (!party) return ;\n\n // Figure out the intro text to show. It's based on the elections the parties are running for.\n let introText;\n const dkRunning = party.dk && party.dk.state !== CollectionState.noCollection;\n const euRunning = party.eu && party.eu.state !== CollectionState.noCollection;\n\n if (dkRunning && euRunning) introText = introLabels?.all;\n else if (dkRunning) introText = introLabels?.dk;\n else if (euRunning) introText = introLabels?.eu;\n\n // Get the collection state for the party\n const collectionState: CollectionState =\n party && party[electionTypeValue]\n ? (party[electionTypeValue].state as CollectionState)\n : CollectionState.noCollection;\n\n return (\n \n {process.env.NODE_ENV !== 'test' && }\n \n \n {party.name}\n \n {introText && (\n