Skip to content

Commit f1dfa66

Browse files
committed
✨ Sorter linjer etter quays
1 parent e40ede2 commit f1dfa66

File tree

9 files changed

+268
-48
lines changed

9 files changed

+268
-48
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
'use client'
2+
import { Checkbox } from '@entur/form'
3+
import { TransportIcon } from 'app/(admin)/tavler/[id]/rediger/components/Settings/components/TransportIcon'
4+
import { EventProps } from 'app/posthog/events'
5+
import { usePosthogTracking } from 'app/posthog/usePosthogTracking'
6+
import { useState } from 'react'
7+
import { BoardTileDB } from 'src/types/db-types/boards'
8+
import { TTransportMode } from 'src/types/graphql-schema'
9+
import { TLineFragment } from './types'
10+
11+
function PlatformAndLines({
12+
tile,
13+
groupKey,
14+
title,
15+
lines,
16+
trackingLocation,
17+
transportMode,
18+
}: {
19+
tile: BoardTileDB
20+
groupKey: string
21+
title: string
22+
lines: TLineFragment[]
23+
trackingLocation: EventProps<'stop_place_edit_interaction'>['location']
24+
transportMode: TTransportMode | null
25+
}) {
26+
const posthog = usePosthogTracking()
27+
28+
const lineElements = document.getElementsByName(`${tile.uuid}-${groupKey}`)
29+
30+
const anyLineInWhitelist = lines.some((l) =>
31+
tile.whitelistedLines?.includes(l.id),
32+
)
33+
const missingLinesInWhitelist = lines.some(
34+
(l) => !tile.whitelistedLines?.includes(l.id),
35+
)
36+
37+
const defaultChecked = () => {
38+
if (missingLinesInWhitelist && anyLineInWhitelist)
39+
return 'indeterminate'
40+
return (
41+
!tile.whitelistedLines ||
42+
tile.whitelistedLines.length === 0 ||
43+
!missingLinesInWhitelist
44+
)
45+
}
46+
const [checked, setChecked] = useState<boolean | 'indeterminate'>(
47+
defaultChecked(),
48+
)
49+
50+
const determineAllChecked = () => {
51+
let count = 0
52+
for (const l of lineElements.values()) {
53+
if (l instanceof HTMLInputElement) {
54+
if (l.checked === true) count++
55+
}
56+
}
57+
if (count === 0) setChecked(false)
58+
else if (count < lineElements.length) setChecked('indeterminate')
59+
else setChecked(true)
60+
}
61+
62+
return (
63+
<div className="rounded-lg border-2 p-4">
64+
<div className="flex flex-row justify-between">
65+
<div className="flex flex-row items-center justify-start gap-4 font-semibold">
66+
<TransportIcon
67+
transportMode={transportMode}
68+
className={`h-7 w-7 text-white bg-${transportMode} rounded-md p-1`}
69+
/>
70+
{title}
71+
</div>
72+
<Checkbox
73+
checked={checked}
74+
onChange={(e) => {
75+
posthog.capture('stop_place_edit_interaction', {
76+
location: trackingLocation,
77+
field: 'lines',
78+
column_value: 'none',
79+
action: e.target.checked ? 'select_all' : 'cleared',
80+
})
81+
setChecked(e.currentTarget.checked)
82+
lineElements.forEach((input) => {
83+
if (input instanceof HTMLInputElement)
84+
input.checked = e.currentTarget.checked
85+
})
86+
}}
87+
/>
88+
</div>
89+
{checked &&
90+
lines.map((line) => (
91+
<Checkbox
92+
name={`${tile.uuid}-${groupKey}`}
93+
defaultChecked={
94+
!tile.whitelistedLines ||
95+
tile.whitelistedLines.length === 0 ||
96+
tile.whitelistedLines.includes(line.id)
97+
}
98+
key={line.id}
99+
value={line.id}
100+
className="pl-6"
101+
onChange={() => {
102+
posthog.capture('stop_place_edit_interaction', {
103+
location: trackingLocation,
104+
field: 'lines',
105+
column_value: 'none',
106+
action: 'changed',
107+
})
108+
determineAllChecked()
109+
}}
110+
>
111+
<div className="flex flex-row items-center gap-1">
112+
{line.publicCode && (
113+
<div
114+
className={`publicCode bg-${transportMode} text-white`}
115+
>
116+
{line.publicCode}
117+
</div>
118+
)}
119+
{line.name}
120+
</div>
121+
</Checkbox>
122+
))}
123+
</div>
124+
)
125+
}
126+
127+
export { PlatformAndLines }

tavla/app/(admin)/tavler/[id]/rediger/components/TileCard/components/SetVisibleLines.tsx

Lines changed: 75 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,94 @@ import { HiddenInput } from 'app/(admin)/components/Form/HiddenInput'
33
import { TileContext } from 'app/(admin)/tavler/[id]/rediger/components/TileCard/context'
44
import { EventProps } from 'app/posthog/events'
55
import { useNonNullContext } from 'src/hooks/useNonNullContext'
6-
import { TTransportMode } from 'src/types/graphql-schema'
7-
import { TransportModeAndLines } from '../TransportModeAndLines'
6+
import { TQuay, TTransportMode } from 'src/types/graphql-schema'
7+
import { PlatformAndLines } from '../PlatformAndLines'
88
import { TLineFragment } from '../types'
9-
import { sortLineByPublicCode } from '../utils'
9+
import { transportModeNames } from '../utils'
1010

1111
function SetVisibleLines({
12-
uniqLines,
13-
transportModes,
12+
quays,
13+
allLines,
1414
trackingLocation,
1515
}: {
16-
uniqLines: TLineFragment[]
17-
transportModes: (TTransportMode | null)[]
16+
quays: TQuay[]
17+
allLines: TLineFragment[]
1818
trackingLocation: EventProps<'stop_place_edit_interaction'>['location']
1919
}) {
2020
const tile = useNonNullContext(TileContext)
21-
const linesByModeSorted = transportModes
22-
.map((transportMode) => ({
23-
transportMode,
24-
lines: uniqLines
25-
.filter((line) => line.transportMode === transportMode)
26-
.sort(sortLineByPublicCode),
27-
}))
28-
.sort((a, b) => b.lines.length - a.lines.length)
21+
22+
// Group Quays by Transport Mode
23+
const quaysByTransportMode = Object.values(
24+
quays.reduce(
25+
(acc, quay) => {
26+
let mode: TTransportMode = 'unknown'
27+
if (quay.lines.length > 0) {
28+
mode =
29+
(quay.lines[0]?.transportMode as TTransportMode) ||
30+
'unknown'
31+
} else if (
32+
quay.stopPlace?.transportMode &&
33+
quay.stopPlace.transportMode.length > 0
34+
) {
35+
mode =
36+
(quay.stopPlace.transportMode[0] as TTransportMode) ||
37+
'unknown'
38+
}
39+
40+
if (!acc[mode]) {
41+
acc[mode] = {
42+
mode: mode as TTransportMode,
43+
label: transportModeNames(mode) || 'Ukjent',
44+
quays: [],
45+
}
46+
}
47+
48+
acc[mode]?.quays.push(quay)
49+
return acc
50+
},
51+
{} as Record<
52+
string,
53+
{ mode: TTransportMode; label: string; quays: TQuay[] }
54+
>,
55+
),
56+
).sort((a, b) => a.label.localeCompare(b.label))
2957

3058
return (
3159
<>
32-
<Heading4>Transportmidler og linjer</Heading4>
33-
<div className="flex flex-col gap-4 md:flex-row">
34-
{linesByModeSorted.map(({ transportMode, lines }) => (
35-
<TransportModeAndLines
36-
key={transportMode}
37-
tile={tile}
38-
transportMode={transportMode}
39-
lines={lines}
40-
trackingLocation={trackingLocation}
41-
/>
60+
<Heading4>Plattformer og linjer</Heading4>
61+
<div className="flex flex-col gap-8 md:flex-row">
62+
{quaysByTransportMode.map(({ mode, quays }) => (
63+
<div key={mode} className="flex flex-col gap-4">
64+
{quays
65+
.sort((a, b) =>
66+
(a.publicCode || '').localeCompare(
67+
b.publicCode || '',
68+
undefined,
69+
{ numeric: true },
70+
),
71+
)
72+
.map((quay) => {
73+
const title =
74+
quay.name && quay.publicCode
75+
? `${mode === 'metro' || mode === 'rail' ? 'Spor' : 'Plattform'} ${quay.publicCode}`
76+
: quay.name || 'Ukjent'
77+
78+
return (
79+
<PlatformAndLines
80+
key={quay.id}
81+
tile={tile}
82+
groupKey={quay.publicCode || quay.id}
83+
title={title}
84+
lines={quay.lines}
85+
trackingLocation={trackingLocation}
86+
transportMode={mode as TTransportMode}
87+
/>
88+
)
89+
})}
90+
</div>
4291
))}
4392
</div>
44-
<HiddenInput id="count" value={uniqLines.length.toString()} />
93+
<HiddenInput id="count" value={allLines.length.toString()} />
4594
</>
4695
)
4796
}

tavla/app/(admin)/tavler/[id]/rediger/components/TileCard/index.tsx

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -131,19 +131,37 @@ function TileCard({
131131
setIsOpen(false)
132132
}
133133

134-
let lines = useLines(tile)
134+
const quays = useLines(tile)
135135

136-
if (!lines)
136+
if (!quays)
137137
return (
138138
<div className="flex items-center justify-between rounded p-4">
139139
Laster...
140140
</div>
141141
)
142142

143-
// TODO: remove when old lines no longer return any data (2025)
144-
lines = lines.filter((line) => !OLD_LINE_IDS.includes(line.id))
143+
// Filter lines: remove OLD_LINE_IDS
144+
const quaysWithFilteredLines = quays
145+
.map((q) => ({
146+
...q,
147+
lines: q.lines.filter((line) => !OLD_LINE_IDS.includes(line.id)),
148+
}))
149+
.filter((q) => q.lines.length > 0)
145150

146-
const uniqLines = uniqBy(lines, 'id')
151+
// Flatten lines for other components if needed, or update components to use Quays
152+
const allLines = quaysWithFilteredLines.flatMap((q) =>
153+
q.lines.map((l) => ({
154+
...l,
155+
quayName: q.name,
156+
quayPublicCode: q.publicCode,
157+
})),
158+
)
159+
160+
// uniqLines logic might be needed for SetVisibleLines' count,
161+
// but SetVisibleLines now needs Quays.
162+
// Let's pass Quays to SetVisibleLines instead of uniqLines.
163+
164+
const uniqLines = uniqBy(allLines, 'id')
147165

148166
const transportModes = uniqBy(uniqLines, 'transportMode')
149167
.map((l) => l.transportMode)
@@ -200,7 +218,7 @@ function TileCard({
200218
<div className="flex flex-row">
201219
<div
202220
className={`flex w-full items-center justify-between bg-white px-6 py-4 ${
203-
isOpen ? 'rounded-t border-b-2' : 'rounded'
221+
isOpen ? 'rounded-t' : 'rounded'
204222
}`}
205223
>
206224
<div className="flex flex-row items-center gap-4">
@@ -234,7 +252,7 @@ function TileCard({
234252

235253
<BaseExpand open={isOpen}>
236254
<div
237-
className={`mr-14 bg-white px-6 py-4 ${
255+
className={`mr-14 border-t-2 bg-white px-6 py-4 ${
238256
totalTiles == 1 && 'w-full'
239257
} rounded-b`}
240258
>
@@ -262,8 +280,8 @@ function TileCard({
262280
trackingLocation={trackingLocation}
263281
/>
264282
<SetVisibleLines
265-
uniqLines={uniqLines}
266-
transportModes={transportModes}
283+
quays={quaysWithFilteredLines}
284+
allLines={uniqLines}
267285
trackingLocation={trackingLocation}
268286
/>
269287
<SaveCancelDeleteTileButtonGroup

tavla/app/(admin)/tavler/[id]/rediger/components/TileCard/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ export type TLineFragment = {
66
publicCode: string | null
77
name: string | null
88
transportMode: TTransportMode | null
9+
quayName?: string | null
10+
quayPublicCode?: string | null
911
}

tavla/app/(admin)/tavler/[id]/rediger/components/TileCard/useLines.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ import { CLIENT_NAME, GRAPHQL_ENDPOINTS } from 'src/assets/env'
33
import { QuayEditQuery, StopPlaceEditQuery } from 'src/graphql/index'
44
import { BoardTileDB } from 'src/types/db-types/boards'
55
import { TQuay } from 'src/types/graphql-schema'
6-
import { TLineFragment } from './types'
76

8-
function useLines(tile: BoardTileDB): TLineFragment[] | null {
9-
const [lines, setLines] = useState(null)
7+
function useLines(tile: BoardTileDB): TQuay[] | null {
8+
const [quays, setQuays] = useState<TQuay[] | null>(null)
109

1110
useEffect(() => {
1211
fetch(GRAPHQL_ENDPOINTS['journey-planner'], {
@@ -25,16 +24,13 @@ function useLines(tile: BoardTileDB): TLineFragment[] | null {
2524
return res.json()
2625
})
2726
.then((res) => {
28-
if (tile.type === 'quay') setLines(res.data?.quay?.lines ?? [])
29-
else
30-
setLines(
31-
res.data?.stopPlace?.quays?.flatMap(
32-
(q: TQuay) => q?.lines,
33-
) || [],
34-
)
27+
if (tile.type === 'quay') {
28+
const quay = res.data?.quay
29+
setQuays(quay ? [quay] : [])
30+
} else setQuays(res.data?.stopPlace?.quays ?? [])
3531
})
3632
}, [tile])
37-
return lines
33+
return quays
3834
}
3935

4036
export { useLines }

tavla/src/graphql/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ export const QuayCoordinatesQuery = new TypedDocumentString(`
186186
export const QuayEditQuery = new TypedDocumentString(`
187187
query quayEdit($placeId: String!) {
188188
quay(id: $placeId) {
189+
id
190+
publicCode
191+
name
189192
...lines
190193
}
191194
}
@@ -318,7 +321,13 @@ export const StopPlaceEditQuery = new TypedDocumentString(`
318321
query stopPlaceEdit($placeId: String!) {
319322
stopPlace(id: $placeId) {
320323
name
321-
quays(filterByInUse: true) {
324+
quays {
325+
id
326+
publicCode
327+
name
328+
stopPlace {
329+
transportMode
330+
}
322331
...lines
323332
}
324333
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
query quayEdit($placeId: String!) {
22
quay(id: $placeId) {
3+
id
4+
publicCode
5+
name
36
...lines
47
}
58
}

0 commit comments

Comments
 (0)