• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hasadna / open-bus-map-search / 13587892471

28 Feb 2025 12:13PM UTC coverage: 80.622% (+0.04%) from 80.587%
13587892471

Pull #1049

github

web-flow
Merge c8b1f4807 into d2ce4fb5f
Pull Request #1049: feat: added gtfs manual link

358 of 510 branches covered (70.2%)

Branch coverage included in aggregate %.

1 of 3 new or added lines in 1 file covered. (33.33%)

990 of 1162 relevant lines covered (85.2%)

87512.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.25
/src/pages/components/map-related/MapLayers/BusToolTip.tsx
1
import { ReactNode, useEffect, useState } from 'react'
2
import { Link } from 'react-router-dom'
3
import { Button } from '@mui/material'
4
import moment from 'moment-timezone'
5
import './BusToolTip.scss'
6
import { SiriRideWithRelatedPydanticModel } from 'open-bus-stride-client/openapi/models/SiriRideWithRelatedPydanticModel'
7
import { useTranslation } from 'react-i18next'
8
import CircularProgress from '@mui/material/CircularProgress'
9
import cn from 'classnames'
10
import CustomTreeView from '../../CustomTreeView'
11
import { EasterEgg } from '../../../EasterEgg/EasterEgg'
12
import ComplaintModal from './ComplaintModal'
13
import { getSiriRideWithRelated } from 'src/api/siriService'
14
import type { Point } from 'src/pages/timeBasedMap'
15

16
export type BusToolTipProps = { position: Point; icon: string; children?: ReactNode }
17
const manualUrl: string =
18
  'https://www.gov.il/BlobFolder/generalpage/gtfs_general_transit_feed_specifications/he/GTFS_Developer_Information_2024.11.21b.pdf'
24✔
19

20
export function BusToolTip({ position, icon, children }: BusToolTipProps) {
24✔
21
  const [siriRide, setSiriRide] = useState<SiriRideWithRelatedPydanticModel | undefined>()
50✔
22
  const [isLoading, setIsLoading] = useState(false)
50✔
23
  const [showJson, setShowJson] = useState(false)
50✔
24
  const { t, i18n } = useTranslation()
50✔
25
  const [modalOpen, setModalOpen] = useState(false)
50✔
26

27
  useEffect(() => {
50✔
28
    setIsLoading(true)
8✔
29
    getSiriRideWithRelated(
8✔
30
      position.point!.siri_route__id.toString(),
31
      position.point!.siri_ride__vehicle_ref.toString(),
32
      position.point!.siri_route__line_ref.toString(),
33
    )
34
      .then((siriRideRes: SiriRideWithRelatedPydanticModel) => setSiriRide(siriRideRes))
8✔
35
      .finally(() => setIsLoading(false))
8✔
36
  }, [position])
37

38
  function getDirectionFromAngle(angle: number): string {
39
    // Normalize the angle to the range 0-360
40
    angle = ((angle % 360) + 360) % 360
34✔
41
    // Define the cardinal directions in clockwise order
42
    const directions: string[] = [
34✔
43
      t('directions.North', { defaultValue: 'North' }),
44
      t('directions.Northeast', { defaultValue: 'Northeast' }),
45
      t('directions.East', { defaultValue: 'East' }),
46
      t('directions.Southeast', { defaultValue: 'Southeast' }),
47
      t('directions.South', { defaultValue: 'South' }),
48
      t('directions.Southwest', { defaultValue: 'Southwest' }),
49
      t('directions.West', { defaultValue: 'West' }),
50
      t('directions.Northwest', { defaultValue: 'Northwest' }),
51
    ]
52
    // Divide the angle into 8 equal sections (45 degrees each)
53
    const index: number = Math.round(angle / 45) % 8
34✔
54

55
    return directions[index]
34✔
56
  }
57

58
  return (
59
    <div className={cn('bus-tooltip', { hebrew: i18n.language === 'he' })}>
60
      {isLoading || !siriRide ? (
92✔
61
        <div className="loading">
16✔
62
          <span>{t('loading_routes')}</span>
63
          <CircularProgress />
64
        </div>
65
      ) : (
66
        <>
67
          <header className="header">
68
            <h1 className="title">
69
              {`${t('line')}: `}
70
              <span>
71
                <Link to={`/profile/${siriRide.gtfsRideGtfsRouteId}`}>
72
                  {siriRide.gtfsRouteRouteShortName}
73
                </Link>
74
              </span>
75
            </h1>
76
            <img src={icon} alt="bus icon" className="bus-icon" />
77
          </header>
78
          <div className="content">
79
            <ul>
80
              <li>
81
                {' '}
82
                {`${t('from')}: `}
83
                <span>{siriRide.gtfsRouteRouteLongName?.split('<->')[0]}</span>
84
              </li>
85
              <li>
86
                {`${t('destination')}: `}
87
                <span>{siriRide.gtfsRouteRouteLongName?.split('<->')[1]}</span>
88
              </li>
89
              <li>
90
                {`${t('velocity')}: `}
91
                <span>{`${position.point?.velocity}  ${t('kmh')}`}</span>
92
              </li>
93
              <li>
94
                {`${t('sample_time')}: `}
95
                <span>
96
                  {/* eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion */}
97
                  {moment(position.point!.recorded_at_time as string, moment.ISO_8601)
98
                    .tz('Israel')
99
                    .format(`DD/MM/yyyy [${t('at_time')}] HH:mm`)}
100
                </span>
101
              </li>
102
              <li>
103
                {`${t('vehicle_ref')}: `}
104
                <span>{position.point?.siri_ride__vehicle_ref}</span>
105
              </li>
106
              <li>
107
                {`${t('drive_direction')}: `}
108
                <span>
109
                  {/* ({position.point?.bearing} {t('bearing')}) */}
110
                  {position.point?.bearing} {t('bearing')} (
111
                  {position.point?.bearing !== undefined
34!
112
                    ? getDirectionFromAngle(position.point.bearing)
113
                    : t('unknown', { defaultValue: 'unknown' })}
114
                  )
115
                </span>
116
              </li>
117
              <li>
118
                {`${t('coords')}: `}
119
                <span>{position.loc.join(' ,')}</span>
120
              </li>
121
            </ul>
122
            <Button
123
              sx={i18n.language === 'he' ? { paddingLeft: 0 } : { paddingRight: 0 }}
34!
124
              onClick={() => setShowJson((showJson) => !showJson)}>
8✔
125
              {showJson ? t('hide_document') : t('show_document')}
34✔
126
            </Button>
127

128
            {/* Open Complaint Button */}
129
            <EasterEgg code="complaint">
130
              <Button
131
                variant="contained"
132
                color="success"
133
                onClick={() => setModalOpen((prev) => !prev)}
×
134
                style={{ borderRadius: '50px' }}>
135
                {t('open_complaint')}
136
              </Button>
137
            </EasterEgg>
138

139
            {/* Complaint Modal */}
140
            <ComplaintModal modalOpen={modalOpen} setModalOpen={setModalOpen} position={position} />
141

142
            {showJson && (
34✔
143
              <div onClick={(e) => e.stopPropagation()}>
×
144
                <a
145
                  href={manualUrl}
146
                  target="_blank"
147
                  rel="noreferrer"
148
                  style={{ display: 'flex', padding: '5px', backgroundColor: 'white' }}
NEW
149
                  onMouseEnter={(e) => (e.currentTarget.style.backgroundColor = 'lightgray')}
×
NEW
150
                  onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = 'white')}>
×
151
                  {t('gtfs_manual')}
152
                </a>
153
                <CustomTreeView<Point>
154
                  id={position.point?.id + ''}
155
                  data={position}
156
                  name={t('line')}
157
                />
158
                {siriRide?.gtfsRideId && (
10✔
159
                  <CustomTreeView<SiriRideWithRelatedPydanticModel | undefined>
160
                    id={siriRide?.gtfsRideId + ''}
161
                    data={siriRide}
162
                    name={t('drive_direction')}
163
                  />
164
                )}
165
              </div>
166
            )}
167
          </div>
168
          {children}
169
        </>
170
      )}
171
    </div>
172
  )
173
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc