Skip to content

Commit a5f778b

Browse files
authored
Merge pull request #6384 from espoon-voltti/income-statement-fixes
Tuloselvityksen saavutettavuus- ja UI-parannuksia
2 parents baea16b + 07ff04c commit a5f778b

File tree

16 files changed

+191
-148
lines changed

16 files changed

+191
-148
lines changed

frontend/src/citizen-frontend/income-statements/ChildIncomeStatementAttachments.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
AttachmentId,
1010
IncomeStatementId
1111
} from 'lib-common/generated/api-types/shared'
12-
import { IncomeStatementAttachments } from 'lib-common/income-statements'
12+
import { IncomeStatementAttachments } from 'lib-common/income-statements/attachments'
1313
import { FixedSpaceColumn } from 'lib-components/layout/flex-helpers'
1414
import FileUpload from 'lib-components/molecules/FileUpload'
1515

frontend/src/citizen-frontend/income-statements/ChildIncomeStatementEditor.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import {
1212
IncomeStatementId
1313
} from 'lib-common/generated/api-types/shared'
1414
import { fromUuid } from 'lib-common/id-type'
15+
import { fromBody } from 'lib-common/income-statements/body'
16+
import * as Form from 'lib-common/income-statements/form'
17+
import { emptyIncomeStatementForm } from 'lib-common/income-statements/form'
1518
import LocalDate from 'lib-common/local-date'
1619
import {
1720
constantQuery,
@@ -31,9 +34,6 @@ import {
3134
incomeStatementQuery,
3235
updateIncomeStatementMutation
3336
} from './queries'
34-
import { fromBody } from './types/body'
35-
import * as Form from './types/form'
36-
import { emptyIncomeStatementForm } from './types/form'
3737

3838
interface EditorState {
3939
id: string | undefined

frontend/src/citizen-frontend/income-statements/ChildIncomeStatementForm.tsx

+7-11
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import styled from 'styled-components'
88
import { Result } from 'lib-common/api'
99
import { IncomeStatementStatus } from 'lib-common/generated/api-types/incomestatement'
1010
import { IncomeStatementId } from 'lib-common/generated/api-types/shared'
11-
import { numAttachments } from 'lib-common/income-statements'
11+
import { numAttachments } from 'lib-common/income-statements/attachments'
12+
import * as Form from 'lib-common/income-statements/form'
1213
import LocalDate from 'lib-common/local-date'
1314
import { scrollToRef } from 'lib-common/utils/scrolling'
1415
import { AsyncButton } from 'lib-components/atoms/buttons/AsyncButton'
@@ -31,7 +32,7 @@ import { useLang, useTranslation } from '../localization'
3132
import ChildIncomeStatementAttachments from './ChildIncomeStatementAttachments'
3233
import {
3334
AttachmentSection,
34-
makeAttachmentHandler
35+
useAttachmentHandler
3536
} from './IncomeStatementAttachments'
3637
import {
3738
ActionContainer,
@@ -42,7 +43,6 @@ import {
4243
useFieldDispatch,
4344
useFieldSetState
4445
} from './IncomeStatementComponents'
45-
import * as Form from './types/form'
4646

4747
const OtherInfoContainer = styled.div`
4848
max-width: 716px;
@@ -62,14 +62,10 @@ const ChildIncome = React.memo(function ChildIncome({
6262
const t = useTranslation()
6363

6464
const onAttachmentChange = useFieldSetState(onChange, 'attachments')
65-
const attachmentHandler = useMemo(
66-
() =>
67-
makeAttachmentHandler(
68-
incomeStatementId,
69-
formData.attachments,
70-
onAttachmentChange
71-
),
72-
[formData.attachments, incomeStatementId, onAttachmentChange]
65+
const attachmentHandler = useAttachmentHandler(
66+
incomeStatementId,
67+
formData.attachments,
68+
onAttachmentChange
7369
)
7470

7571
const onOtherInfoChanged = useFieldDispatch(onChange, 'otherInfo')

frontend/src/citizen-frontend/income-statements/ChildIncomeStatementView.tsx

+5-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import { IncomeStatementId } from 'lib-common/generated/api-types/shared'
1010
import {
1111
collectAttachmentIds,
1212
toIncomeStatementAttachments
13-
} from 'lib-common/income-statements'
13+
} from 'lib-common/income-statements/attachments'
14+
import {
15+
computeRequiredAttachments,
16+
fromIncomeStatement
17+
} from 'lib-common/income-statements/form'
1418
import { useQueryResult } from 'lib-common/query'
1519
import { useIdRouteParam } from 'lib-common/useRouteParams'
1620
import HorizontalLine from 'lib-components/atoms/HorizontalLine'
@@ -36,7 +40,6 @@ import {
3640
incomeStatementQuery,
3741
updateSentIncomeStatementMutation
3842
} from './queries'
39-
import { computeRequiredAttachments, fromIncomeStatement } from './types/form'
4043

4144
export default React.memo(function ChildIncomeStatementView() {
4245
const incomeStatementId =

frontend/src/citizen-frontend/income-statements/IncomeStatementAttachments.tsx

+92-77
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// SPDX-License-Identifier: LGPL-2.1-or-later
44

55
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
6-
import React, { useCallback, useMemo } from 'react'
6+
import React, { useCallback, useMemo, useRef } from 'react'
77
import styled from 'styled-components'
88

99
import { Attachment } from 'lib-common/generated/api-types/attachment'
@@ -18,8 +18,7 @@ import {
1818
import {
1919
IncomeStatementAttachments,
2020
numAttachments
21-
} from 'lib-common/income-statements'
22-
import { scrollToElement } from 'lib-common/utils/scrolling'
21+
} from 'lib-common/income-statements/attachments'
2322
import UnorderedList from 'lib-components/atoms/UnorderedList'
2423
import { Button } from 'lib-components/atoms/buttons/Button'
2524
import { ContentArea } from 'lib-components/layout/Container'
@@ -45,7 +44,7 @@ import {
4544
SetStateCallback
4645
} from './IncomeStatementComponents'
4746

48-
function attachmentSectionId(type: IncomeStatementAttachmentType): string {
47+
function attachmentSectionDataQa(type: IncomeStatementAttachmentType): string {
4948
return `attachment-section-${type}`
5049
}
5150

@@ -58,80 +57,104 @@ export interface AttachmentHandler {
5857
onDeleted: (id: AttachmentId) => void
5958
getDownloadUrl: (id: AttachmentId) => string
6059
}
60+
setElement: (
61+
attachmentType: IncomeStatementAttachmentType,
62+
el: HTMLElement | null
63+
) => void
64+
focus: (attachmentType: IncomeStatementAttachmentType) => void
6165
}
6266

6367
/** Returns `undefined` if the income statement contains old untyped attachments */
64-
export function makeAttachmentHandler(
68+
export function useAttachmentHandler(
6569
id: IncomeStatementId | undefined,
6670
attachments: IncomeStatementAttachments,
6771
onChange: SetStateCallback<IncomeStatementAttachments>
6872
): AttachmentHandler | undefined {
69-
if (!attachments.typed) {
70-
// Has untyped attachments
71-
return undefined
72-
}
73-
const { attachmentsByType } = attachments
74-
return {
75-
hasAttachment: (attachmentType: IncomeStatementAttachmentType) =>
76-
!!attachmentsByType[attachmentType]?.length,
77-
fileUploadProps: (attachmentType: IncomeStatementAttachmentType) => {
78-
const files = attachmentsByType[attachmentType] ?? []
79-
return {
80-
files,
81-
uploadHandler: incomeStatementAttachment(id, attachmentType),
82-
onUploaded: (attachment: Attachment) => {
83-
onChange((prev) => {
84-
// Should not happen
85-
if (!prev.typed) return prev
73+
const refs = useRef<
74+
Partial<Record<IncomeStatementAttachmentType, HTMLElement>>
75+
>({})
76+
return useMemo(() => {
77+
if (!attachments.typed) {
78+
// Has untyped attachments
79+
return undefined
80+
}
81+
const { attachmentsByType } = attachments
82+
return {
83+
hasAttachment: (attachmentType: IncomeStatementAttachmentType) =>
84+
!!attachmentsByType[attachmentType]?.length,
85+
fileUploadProps: (attachmentType: IncomeStatementAttachmentType) => {
86+
const files = attachmentsByType[attachmentType] ?? []
87+
return {
88+
files,
89+
uploadHandler: incomeStatementAttachment(id, attachmentType),
90+
onUploaded: (attachment: Attachment) => {
91+
onChange((prev) => {
92+
// Should not happen
93+
if (!prev.typed) return prev
8694

87-
const { attachmentsByType } = prev
88-
if (attachmentsByType[attachmentType]) {
89-
return {
90-
...prev,
91-
attachmentsByType: {
92-
...attachmentsByType,
93-
[attachmentType]: [
94-
...attachmentsByType[attachmentType],
95-
attachment
96-
]
95+
const { attachmentsByType } = prev
96+
if (attachmentsByType[attachmentType]) {
97+
return {
98+
...prev,
99+
attachmentsByType: {
100+
...attachmentsByType,
101+
[attachmentType]: [
102+
...attachmentsByType[attachmentType],
103+
attachment
104+
]
105+
}
97106
}
98-
}
99-
} else {
100-
return {
101-
...prev,
102-
attachmentsByType: {
103-
...attachmentsByType,
104-
[attachmentType]: [attachment]
107+
} else {
108+
return {
109+
...prev,
110+
attachmentsByType: {
111+
...attachmentsByType,
112+
[attachmentType]: [attachment]
113+
}
105114
}
106115
}
107-
}
108-
})
109-
},
110-
onDeleted: (id: AttachmentId) => {
111-
onChange((prev) => {
112-
// Should not happen
113-
if (!prev.typed) return prev
116+
})
117+
},
118+
onDeleted: (id: AttachmentId) => {
119+
onChange((prev) => {
120+
// Should not happen
121+
if (!prev.typed) return prev
114122

115-
const { attachmentsByType } = prev
116-
if (attachmentsByType[attachmentType]) {
117-
return {
118-
...prev,
119-
attachmentsByType: {
120-
...attachmentsByType,
121-
[attachmentType]: attachmentsByType[attachmentType].filter(
122-
(a) => a.id !== id
123-
)
123+
const { attachmentsByType } = prev
124+
if (attachmentsByType[attachmentType]) {
125+
return {
126+
...prev,
127+
attachmentsByType: {
128+
...attachmentsByType,
129+
[attachmentType]: attachmentsByType[attachmentType].filter(
130+
(a) => a.id !== id
131+
)
132+
}
124133
}
134+
} else {
135+
return prev
125136
}
126-
} else {
127-
return prev
128-
}
129-
})
130-
},
131-
getDownloadUrl: () => ''
137+
})
138+
},
139+
getDownloadUrl: () => ''
140+
}
141+
},
142+
setElement: (
143+
attachmentType: IncomeStatementAttachmentType,
144+
el: HTMLElement | null
145+
) => {
146+
if (el) {
147+
refs.current[attachmentType] = el
148+
} else {
149+
delete refs.current[attachmentType]
150+
}
151+
},
152+
focus: (attachmentType: IncomeStatementAttachmentType) => {
153+
const element = refs.current[attachmentType]
154+
if (element) element.focus()
132155
}
133156
}
134-
}
157+
}, [attachments, id, onChange])
135158
}
136159

137160
export const AttachmentSection = React.memo(function AttachmentSection({
@@ -176,7 +199,8 @@ export const AttachmentSection = React.memo(function AttachmentSection({
176199
{labelAndInfo}
177200
{!dense && <Gap size="xs" />}
178201
<FileUpload
179-
id={attachmentSectionId(attachmentType)}
202+
ref={(el) => attachmentHandler.setElement(attachmentType, el)}
203+
data-qa={attachmentSectionDataQa(attachmentType)}
180204
{...fileUploadProps(attachmentType)}
181205
/>
182206
</>
@@ -209,12 +233,7 @@ export const IncomeStatementMissingAttachments = React.memo(
209233
<Button
210234
appearance="link"
211235
onClick={() => {
212-
const element = document.getElementById(
213-
attachmentSectionId(attachmentType)
214-
)
215-
if (element) {
216-
scrollToElement(element, 0, 'center')
217-
}
236+
attachmentHandler.focus(attachmentType)
218237
}}
219238
text={t.income.attachments.attachmentNames[attachmentType]}
220239
/>
@@ -373,14 +392,10 @@ export const CitizenAttachmentsWithUpload = React.memo(
373392
onChange: SetStateCallback<IncomeStatementAttachments>
374393
}) {
375394
const t = useTranslation()
376-
const attachmentHandler = useMemo(
377-
() =>
378-
makeAttachmentHandler(
379-
incomeStatementId,
380-
incomeStatementAttachments,
381-
onChange
382-
),
383-
[incomeStatementAttachments, incomeStatementId, onChange]
395+
const attachmentHandler = useAttachmentHandler(
396+
incomeStatementId,
397+
incomeStatementAttachments,
398+
onChange
384399
)
385400

386401
if (!incomeStatementAttachments.typed) {

frontend/src/citizen-frontend/income-statements/IncomeStatementEditor.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import { combine, Loading, Result } from 'lib-common/api'
99
import { IncomeStatementStatus } from 'lib-common/generated/api-types/incomestatement'
1010
import { IncomeStatementId } from 'lib-common/generated/api-types/shared'
1111
import { fromUuid } from 'lib-common/id-type'
12+
import { fromBody } from 'lib-common/income-statements/body'
13+
import * as Form from 'lib-common/income-statements/form'
14+
import { emptyIncomeStatementForm } from 'lib-common/income-statements/form'
1215
import LocalDate from 'lib-common/local-date'
1316
import {
1417
constantQuery,
@@ -28,9 +31,6 @@ import {
2831
incomeStatementStartDatesQuery,
2932
updateIncomeStatementMutation
3033
} from './queries'
31-
import { fromBody } from './types/body'
32-
import * as Form from './types/form'
33-
import { emptyIncomeStatementForm } from './types/form'
3434

3535
interface EditorState {
3636
id: string | undefined

frontend/src/citizen-frontend/income-statements/IncomeStatementForm.tsx

+7-11
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
otherIncomes
1919
} from 'lib-common/generated/api-types/incomestatement'
2020
import { IncomeStatementId } from 'lib-common/generated/api-types/shared'
21+
import * as Form from 'lib-common/income-statements/form'
2122
import LocalDate from 'lib-common/local-date'
2223
import { scrollToRef } from 'lib-common/utils/scrolling'
2324
import UnorderedList from 'lib-components/atoms/UnorderedList'
@@ -56,9 +57,9 @@ import { useLang, useTranslation } from '../localization'
5657
import {
5758
IncomeStatementUntypedAttachments,
5859
IncomeStatementMissingAttachments,
59-
makeAttachmentHandler,
6060
AttachmentHandler,
61-
AttachmentSection
61+
AttachmentSection,
62+
useAttachmentHandler
6263
} from './IncomeStatementAttachments'
6364
import {
6465
ActionContainer,
@@ -71,7 +72,6 @@ import {
7172
useFieldDispatch,
7273
useFieldSetState
7374
} from './IncomeStatementComponents'
74-
import * as Form from './types/form'
7575

7676
interface Props {
7777
incomeStatementId: IncomeStatementId | undefined
@@ -180,14 +180,10 @@ export default React.memo(
180180
)
181181

182182
const onAttachmentChange = useFieldSetState(onChange, 'attachments')
183-
const attachmentHandler = useMemo(
184-
() =>
185-
makeAttachmentHandler(
186-
incomeStatementId,
187-
formData.attachments,
188-
onAttachmentChange
189-
),
190-
[formData.attachments, incomeStatementId, onAttachmentChange]
183+
const attachmentHandler = useAttachmentHandler(
184+
incomeStatementId,
185+
formData.attachments,
186+
onAttachmentChange
191187
)
192188

193189
const sendButtonEnabled = useMemo(

0 commit comments

Comments
 (0)