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

code4recovery / tsml-ui / 18451009991

12 Oct 2025 11:29PM UTC coverage: 43.532% (-19.9%) from 63.458%
18451009991

Pull #475

github

web-flow
Merge 9d0374e51 into 0a0ddf96f
Pull Request #475: pretty permalinks

369 of 1009 branches covered (36.57%)

Branch coverage included in aggregate %.

15 of 37 new or added lines in 5 files covered. (40.54%)

236 existing lines in 17 files now uncovered.

553 of 1109 relevant lines covered (49.86%)

4.31 hits per line

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

6.25
/src/hooks/input.tsx
1
import {
2
  createContext,
3
  PropsWithChildren,
4
  useContext,
5
  useEffect,
6
  useState,
7
} from 'react';
8
import { useSearchParams } from 'react-router-dom';
9

10
import { formatString, validateInput } from '../helpers';
11
import { useError } from './error';
12
import { defaults, useSettings } from './settings';
13

14
type Coordinates = {
15
  latitude?: number;
16
  longitude?: number;
17
  waitingForInput: boolean;
18
};
19

20
const InputContext = createContext<
8✔
21
  {
22
    input: TSMLReactConfig['defaults'];
23
    latitude?: number;
24
    longitude?: number;
25
    setBounds: (bounds: {
26
      north: string;
27
      south: string;
28
      east: string;
29
      west: string;
30
    }) => void;
31
  } & Coordinates
32
>({ input: defaults.defaults, waitingForInput: false, setBounds: () => {} });
33

34
export const InputProvider = ({ children }: PropsWithChildren) => {
8✔
UNCOV
35
  const { setError } = useError();
×
UNCOV
36
  const [searchParams] = useSearchParams();
×
UNCOV
37
  const { settings, strings } = useSettings();
×
UNCOV
38
  const [bounds, setBounds] = useState({
×
39
    north: '',
40
    south: '',
41
    east: '',
42
    west: '',
43
  });
44

UNCOV
45
  const [input, setInput] = useState<TSMLReactConfig['defaults']>(
×
46
    validateInput(searchParams)
47
  );
48

UNCOV
49
  const [coordinates, setCoordinates] = useState<Coordinates>({
×
50
    waitingForInput: input.mode !== 'search',
51
  });
52

53
  // detect input from URL search params
UNCOV
54
  useEffect(() => {
×
UNCOV
55
    setInput(validateInput(searchParams));
×
56
  }, [searchParams]);
57

58
  // handle geocoding or geolocation requests
UNCOV
59
  useEffect(() => {
×
UNCOV
60
    if (coordinates.waitingForInput || !bounds.north) return;
×
61
    setError();
×
62
    if (input.mode === 'location' && input.search) {
×
63
      setCoordinates({ waitingForInput: true });
×
64
      const url = window.location.hostname.endsWith('.test')
×
65
        ? 'geo.test'
66
        : 'geo.code4recovery.org';
67
      fetch(
×
68
        `https://${url}/api/geocode?${new URLSearchParams({
69
          application: 'tsml-ui',
70
          language: settings.language,
71
          referrer: window.location.href,
72
          search: input.search,
73
          ...bounds,
74
        })}`
75
      )
76
        .then(result => result.json())
×
77
        .then(({ results }) => {
78
          if (!results?.length) {
×
79
            throw new Error(
×
80
              formatString(strings.errors.geocoding, { address: input.search })
81
            );
82
          }
83
          const { geometry } = results[0];
×
84
          setCoordinates({
×
85
            latitude: geometry.location.lat,
86
            longitude: geometry.location.lng,
87
            waitingForInput: false,
88
          });
89
        })
90
        .catch(e => {
91
          setError(String(e));
×
92
          setCoordinates({
×
93
            latitude: undefined,
94
            longitude: undefined,
95
            waitingForInput: false,
96
          });
97
        });
98
    } else if (input.mode === 'me') {
×
99
      setCoordinates({ waitingForInput: true });
×
100
      setError();
×
101
      navigator.geolocation.getCurrentPosition(
×
102
        position => {
103
          setCoordinates({
×
104
            latitude: position.coords.latitude,
105
            longitude: position.coords.longitude,
106
            waitingForInput: false,
107
          });
108
        },
109
        () => {
110
          setError(strings.errors.geolocation);
×
111
          setCoordinates({
×
112
            waitingForInput: false,
113
          });
114
        },
115
        { timeout: 5000 }
116
      );
117
    } else {
118
      setCoordinates({ waitingForInput: false });
×
119
    }
120
  }, [input.mode, input.search, bounds.north]);
121

UNCOV
122
  return (
×
123
    <InputContext.Provider value={{ input, setBounds, ...coordinates }}>
124
      {children}
125
    </InputContext.Provider>
126
  );
127
};
128

129
export const useInput = () => useContext(InputContext);
14✔
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

© 2026 Coveralls, Inc