react-use#useOrientation JavaScript Examples

The following examples show how to use react-use#useOrientation. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: App.js    From FSE-Planner with MIT License 4 votes vote down vote up
function App() {

  const [filtersBar, setFiltersBar] = React.useState(false)
  const [filters, setFilters] = React.useState({
    type: 'Trip-Only',
    cargo: ['passengers'],
    fromIcao: null,
    toIcao: null,
    minPax: '',
    minKg: '',
    maxPax: '',
    maxKg: '',
    minDist: '',
    maxDist: '',
    minJobPay: '',
    minLegPay: '',
    percentPay: '',
    direction: ''
  });
  const [table, setTable] = React.useState(false);
  const [updatePopup, setUpdatePopup] = React.useState(false);
  const [settingsPopup, setSettingsPopup] = React.useState(false);
  const [creditsPopup, setCreditsPopup] = React.useState(false);
  const [jobs, setJobs] = React.useState(() => {
    return transformJobs(storage.get('jobs', {}, true));
  });
  const [planes, setPlanes] = React.useState(() => {
    return transformPlanes(storage.get('planes', {}));
  });
  const [flight, setFlight] = React.useState(() => {
    return transformJobs(storage.get('flight', {}));
  });
  const [settings, setSettings] = React.useState(() => {
    const obj = {};
    // Cannot use _defaultsDeep, because it messes up with array
    [defaultSettings, storage.get('settings', {})].forEach(item => {
      _mergeWith(obj, item, (objectValue, sourceValue) => {
        return _isArray(sourceValue) ? sourceValue : undefined;
      });
    });
    return obj;
  });
  const [search, setSearch] = React.useState(null);
  const [searchDest, setSearchDest] = React.useState(null);
  const [searchInput, setSearchInput] = React.useState('');
  const [searchHistory, setSearchHistory] = React.useState(storage.get('searchHistory', []));
  const [icaodata, setIcaodata] = React.useState(icaodataSrc);
  const [isTourOpen, setIsTourOpen] = React.useState(storage.get('tutorial') === null);
  const [routeFinder, setRouteFinder] = React.useState(false);
  const [route, setRoute] = React.useState(null);
  const [searchOptions, setSearchOptions] = React.useState([]);
  const mapRef = React.useRef();
  const searchDestRef = React.useRef(null);
  const orientation = useOrientation();
  const windowSize = useWindowSize();

  const options = React.useMemo(() => ({
    jobs: jobs,
    planes: planes,
    flight: flight,
    settings: settings,
    icaodata: icaodata,
    ...filters
  }), [jobs, planes, flight, settings, icaodata, filters]);

  React.useEffect(() => {
    const obj = _clone(icaodataSrc);
    icaos.forEach((icao) => {
      const nb = wrap(obj[icao].lon, settings.display.map.center);
      obj[icao].lon += nb;
    });
    setIcaodata(obj);
  }, [settings.display.map.center]);

  React.useEffect(() => {
    // Display changelog if new version
    const last = storage.get('tutorial');
    if (last && last !== process.env.REACT_APP_VERSION) {
      setCreditsPopup(true);
      storage.set('tutorial', process.env.REACT_APP_VERSION);
    }

    // Set search if query string in URL
    const urlParams = new URLSearchParams(window.location.search);
    const icao = urlParams.get('icao');
    if (icao) {
      setSearch(icao);
    }

    // Register error logging
    window.onerror = (message, file, line, column, errorObject) => {
      // We do not use ErrorBoundary component for logging, because it does
      // not detect errors in event handlers, and we need to log these errors too
      log.error(message, {
        file: file,
        line: line,
        column: column,
        obj: errorObject,
      });
    }

  }, []);

  // Create goTo function, to allow panning to given ICAO
  // Cannot just use setSearch, because need to pan even if the ICAO was already in search var
  const goToRef = React.useRef(null);
  const goTo = React.useCallback((icao, from = null) => {
    if (icao) {
      if (from) {
        searchDestRef.current = {...icaodataSrc[icao], from: from};
        setSearchDest(icao);
        setSearch(from);
        setSearchOptions([searchDestRef.current]);
        setSearchHistory(prevList => {
          const list = [...(new Set([icao, from, ...prevList]))].slice(0, 5);
          storage.set('searchHistory', list);
          return list;
        });
        window.history.replaceState({icao:from}, '', '?icao='+from);
      }
      else {
        setSearch(prevIcao => prevIcao === icao ? null : icao);
        setSearchDest(null);
        setSearchOptions([icaodataSrc[icao]]);
        goToRef.current = icao;
        setSearchHistory(prevList => {
          const list = [...(new Set([icao, ...prevList]))].slice(0, 5);
          storage.set('searchHistory', list);
          return list;
        });
        window.history.replaceState({icao:icao}, '', '?icao='+icao);
      }
    }
    else {
      setSearch(null);
      window.history.replaceState(null, '', '?');
    }
  }, []);
  React.useEffect(() => {
    if (goToRef.current) {
      const icao = goToRef.current;
      goToRef.current = null;
      setSearch(icao);
    }
  }, [search]);

  // Invalidate map size when routing toogled
  React.useEffect(() => {
    if (!mapRef.current) { return; }
    if (window.scrollY !== 0) {
      window.scrollTo(0, 0);
    }
    mapRef.current.invalidateSize({pan:false});
  }, [routeFinder, filters, orientation, table, windowSize.width, windowSize.height]);

  // Actions
  const actions = React.useRef(null);
  const setActions = () => {
    actions.current = {
      goTo: goTo,
      fromIcao: (icao) => setFilters(prev => {
        const f = {...prev};
        f.fromIcao = icao;
        return f;
      }),
      isFromIcao: (icao) => filters.fromIcao === icao,
      isToIcao: (icao) => filters.toIcao === icao,
      toIcao: (icao) => setFilters(prev => {
        const f = {...prev};
        f.toIcao = icao;
        return f;
      }),
      contextMenu: (actions.current && actions.current.contextMenu) ? actions.current.contextMenu : undefined,
      measureDistance: () => null,
      openTable: () => { setRouteFinder(false); setTable(true); },
      getCustomLayers: (icao) => [],
      addToCustomLayer: () => null,
      removeFromCustomLayer: () => null
    };
  }
  if (!actions.current) { setActions(); }
  React.useEffect(setActions, [goTo, filters.fromIcao, filters.toIcao]);

  React.useEffect(() => {
    const inputs = searchInput.split(/\s*[><]+\s*/g);
    // Should not be more than 2 ICAOS long
    if (inputs.length > 2) { return setSearchOptions([]); }
    // If typing a second ICAO, the first one should be valid
    if (inputs.length > 1 && !icaodataSrc.hasOwnProperty(inputs[0])) { return setSearchOptions([]); }
    const input = inputs[inputs.length-1];

    let filtered = [];
    // If input is empty and search history is not, display search history
    if (!input && searchHistory.length > 0) {
      filtered = searchHistory.map(icao => icaodataSrc[icao]);
    }
    else {
      // Search for ICAO
      filtered = filter(icaodataSrcArr, { inputValue: input, getOptionLabel: (a) => a.icao });
      // If not enough results, search for city name
      if (filtered.length < 5) {
        const add = filter(icaodataSrcArr, { inputValue: input, getOptionLabel: (a) => a.name });
        filtered = filtered.concat(add.slice(0, 5-filtered.length));
      }
    }
    if (inputs.length === 2) {
      filtered = filtered.map(elm => { return {...elm, from: inputs[0]} });
    }
    if (search) {
      if (searchDest) {
        const exist = filtered.reduce((acc, elm) => acc || (elm.icao === searchDest && elm.from === search), false);
        if (!exist) { filtered.push({...icaodataSrc[searchDest], from: search}) }
      }
      else {
        const exist = filtered.reduce((acc, elm) => acc || (elm.icao === search && !elm.from), false);
        if (!exist) { filtered.push(icaodataSrc[search]) }
      }
    }
    setSearchOptions(filtered);
  }, [searchInput, searchHistory, search, searchDest]);

  return (
    <Box
      sx={{
        display: "flex",
        flexFlow: "column",
        height: "100%"
      }}
    >
      <AppBar position="static">
        <Toolbar>
          <Box
            sx={{
              display: 'flex',
              alignItems: 'flex-end',
              flexWrap: 'wrap'
            }}
          >
            <Typography variant="h6" sx={{ lineHeight: 1, py: 0.4 }}>
              FSE Planner
            </Typography>
            <Tooltip title="Changelog & credits">
              <Button
                sx={{
                  marginLeft: 1,
                  paddingLeft: '2px',
                  paddingRight: '2px',
                  px: 0.5,
                  py: 0,
                  fontWeight: 'normal',
                  color: '#fff',
                  letterSpacing: 'normal',
                  textTransform: 'none',
                  minWidth: 'auto'
                }}
                onClick={() => setCreditsPopup(true)}
                data-tour="Step10"
                size="small"
              >
                v{process.env.REACT_APP_VERSION}
              </Button>
            </Tooltip>
          </Box>
          <Box
            sx={{
              display: "flex",
              flexWrap: "wrap",
              ml: 1,
              flexGrow: 2
            }}
          >
            <Button
              sx={styles.menuBtn}
              onClick={() => setUpdatePopup(true)}
              data-tour="Step2"
              startIcon={<UpdateIcon />}
            >
              Load data
            </Button>
            <Button
              sx={styles.menuBtn}
              onClick={() => {
                if (!table) {
                  setRouteFinder(false);
                }
                setTable(!table);
              }}
              startIcon={table ? <MapIcon /> : <TableViewIcon />}
            >
              {table ? "Map" : "Table" }
            </Button>
            <Button
              sx={{
                ...styles.menuBtn,
                ...(filtersBar && {
                  backgroundColor: 'rgba(255, 255, 255, 0.3)',
                  '&:hover': {
                    backgroundColor: 'rgba(255, 255, 255, 0.3)',
                  }
                })
              }}
              onClick={() => setFiltersBar(!filtersBar)}
              data-tour="Step7"
              startIcon={<FilterAltIcon />}
            >
              Filters
            </Button>
            <Button
              sx={{
                ...styles.menuBtn,
                ...(routeFinder && {
                  backgroundColor: 'rgba(255, 255, 255, 0.3)',
                  '&:hover': {
                    backgroundColor: 'rgba(255, 255, 255, 0.3)',
                  }
                })
              }}
              onClick={() => {
                if (table) {
                  setTable(false);
                  setRouteFinder(true);
                }
                else {
                    setRouteFinder(!routeFinder)
                }
              }}
              data-tour="Step9"
              startIcon={<DirectionsIcon />}
            >
              Route finder
            </Button>
            <Button
              sx={styles.menuBtn}
              onClick={() => setSettingsPopup(true)}
              startIcon={<TuneIcon />}
            >
              Settings
            </Button>
          </Box>
          <Box
            sx={{
              display: 'flex',
              ml: 2
            }}
          >
            <Autocomplete
              options={searchOptions}
              getOptionLabel={(a) => a.icao ? (a.from ? a.from + ' > ' + a.icao : a.icao) : ''}
              renderOption={(props, a) =>
                <li {...props}>
                  <Box
                    component="span"
                    sx={{
                      display: 'flex',
                      alignItems: 'center',
                      overflow: 'hidden'
                    }}
                  >
                    {a.from &&
                      <React.Fragment>
                        <Box
                          component="b"
                          sx={{
                            minWidth: '40px',
                            textAlign: 'center'
                          }}
                        >
                          {a.from}
                        </Box>
                        <Box
                          component="span"
                          sx={{ px: 1}}
                        >
                          &gt;
                        </Box>
                      </React.Fragment>
                    }
                    <Box
                      component="b"
                      sx={{
                        minWidth: '40px',
                        textAlign: 'center'
                      }}
                    >
                      {a.icao}
                    </Box>
                    <Box
                      component="span"
                      sx={{
                        display: 'flex',
                        flexDirection: 'column',
                        marginLeft: 2,
                        overflow: 'hidden',
                      }}
                    >
                      <Box
                        component="span"
                        sx={{
                          textOverflow: 'ellipsis',
                          overflow: 'hidden',
                          whiteSpace: 'nowrap'
                        }}
                      >
                        {a.name}
                      </Box>
                      <Typography
                        variant="caption"
                        sx={{
                          textOverflow: 'ellipsis',
                          overflow: 'hidden',
                          whiteSpace: 'nowrap',
                          color: '#aaa'
                        }}
                      >
                        {a.city}, {a.state ? a.state+', ' : ''}{a.country}
                      </Typography>
                    </Box>
                  </Box>
                </li>
              }
              filterOptions={x => x}
              renderInput={(params) =>
                <InputBase
                  placeholder="Search..."
                  sx={styles.inputSearch}
                  ref={params.InputProps.ref}
                  inputProps={params.inputProps}
                  endAdornment={params.inputProps.value ?
                      <IconButton
                        size="small"
                        onClick={() => {
                          setSearchDest(null);
                          setSearch(null);
                          setSearchInput('');
                          window.history.replaceState(null, '', '?');
                        }}
                      >
                        <CloseIcon />
                      </IconButton>
                    :
                      null
                  }
                />
              }
              isOptionEqualToValue={(option, value) => option.icao === value.icao && option.from === value.from}
              PopperComponent={PopperMy}
              onChange={(evt, value) => value && goTo(value.icao, value.from)}
              value={search ? (searchDest ? searchDestRef.current : icaodataSrc[search]) : null}
              inputValue={searchInput}
              onInputChange={(evt, value) => setSearchInput(value)}
              autoHighlight={true}
              selectOnFocus={false}
            />
          </Box>
        </Toolbar>
        {filtersBar &&
          <Filters
            filters={filters}
            setFilters={setFilters}
            icaodata={icaodata}
            actions={actions}
            setSettingsPopup={setSettingsPopup}
          />
        }
      </AppBar>
      <Box
        sx={{
          display: 'flex',
          flexWrap: 'nowrap',
          flexGrow: '1',
          overflow: 'hidden'
        }}
      >
        <Routing
          options={options}
          setRoute={setRoute}
          hidden={!routeFinder}
          mapRef={mapRef}
          close={() => setRouteFinder(false)}
          actions={actions}
        />
        <FSEMap
          options={options}
          search={search}
          searchDest={searchDest}
          icaos={icaos}
          route={route}
          mapRef={mapRef}
          actions={actions}
          hidden={table}
        />
        <Table
          options={options}
          hidden={!table}
          actions={actions}
          search={search}
          searchDest={searchDest}
        />
      </Box>
      <UpdatePopup
        open={updatePopup}
        setUpdatePopup={setUpdatePopup}
        setJobs={(jobs) => setJobs(transformJobs(jobs))}
        setPlanes={(planes) => setPlanes(transformPlanes(planes))}
        setFlight={(flight) => setFlight(transformJobs(flight))}
        icaodata={icaodata}
        icaos={icaos}
        settings={settings}
      />
      <SettingsPopup
        open={settingsPopup}
        handleClose={() => setSettingsPopup(false)}
        settings={settings}
        setSettings={setSettings}
        defaultSettings={defaultSettings}
      />
      <CreditsPopup
        open={creditsPopup}
        handleClose={() => setCreditsPopup(false)}
        openTutorial={() => setIsTourOpen(true)}
      />
      <Tour
        isTourOpen={isTourOpen}
        setIsTourOpen={setIsTourOpen}
        updatePopup={updatePopup}
        setUpdatePopup={setUpdatePopup}
      />
    </Box>
  );
}