Skip to content

Commit

Permalink
Add location hash controlled settings (#157)
Browse files Browse the repository at this point in the history
Resolves #156

Allows certain User settings to be overridden via URL hash parameters.
userSlice initialState will attempt to fetch values from URL hash, then
fall back to localStorage or defaults.

Example usage:
```
http://localhost:5173/29.352,-95.460#user-altitude=MSL&user-speed-unit=m/s&user-temperature-unit=%C2%B0C&user-height-unit=m&user-time-format=12-hour&user-distance-unit=km
```
  • Loading branch information
dopplerreflect authored Sep 9, 2024
1 parent 92491b5 commit ac15779
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 24 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,15 @@ Using a reverse proxy such as Nginx, configure the following:
- **IMPORTANT!** For each outgoing API request, make sure to:
- Attach a `User-Agent` header, as per [NOAA](https://www.weather.gov/documentation/services-web-api) and [Nominatim](https://operations.osmfoundation.org/policies/nominatim/) usage policies.
- **Keep these free APIs free - be a good API consumer!** Add caching for each route - I recommend at least 10 minutes for `rucsoundings.noaa.gov`, and one week for `nominatim.openstreetmap.org`.

## Linking to ppg.report

Your app and/or website can better integrate with ppg.report by setting unit of measure and locale settings for the user.

Use the following link format:

```
http://ppg.report/29.352,-95.460#user-altitude=MSL&user-speed-unit=m/s&user-temperature-unit=%C2%B0C&user-height-unit=m&user-time-format=12-hour&user-distance-unit=km
```

Options can be found in [settingEnums.ts](./src/features/rap/extra/settings/settingEnums.ts).
17 changes: 17 additions & 0 deletions src/features/user/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const LOCATIONS_STORAGE_KEY = "user-locations";
export const ALTITUDE_STORAGE_KEY = "user-altitude";
export const ALTITUDE_LEVELS_STORAGE_KEY = "user-altitude-levels";
export const HEIGHT_UNIT_STORAGE_KEY = "user-height-unit";
export const SPEED_UNIT_STORAGE_KEY = "user-speed-unit";
export const TEMPERATURE_UNIT_STORAGE_KEY = "user-temperature-unit";
export const DISTANCE_UNIT_STORAGE_KEY = "user-distance-unit";
export const TIME_FORMAT_STORAGE_KEY = "user-time-format";
export const DISCUSSION_LAST_VIEWED_STORAGE_KEY = "discussion-last-viewed";
export const READ_ALERTS = "read-alerts";
export const HIDDEN_ALERTS = "hidden-alerts";
export const SWIPE_INERTIA_STORAGE_KEY = "swipe-inertia";
export const G_AIRMET_READ_STORAGE_KEY = "g-airmet-read";
export const LANGUAGE_STORAGE_KEY = "user-language";
export const ADVANCED_STORAGE_KEY = "advanced-mode";
export const MAX_LOCATIONS = 5;
export const MAX_DISTANCE_MATCH = 1000; // meters
91 changes: 91 additions & 0 deletions src/features/user/locationHash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import {
ALTITUDE_STORAGE_KEY,
ALTITUDE_LEVELS_STORAGE_KEY,
HEIGHT_UNIT_STORAGE_KEY,
SPEED_UNIT_STORAGE_KEY,
TEMPERATURE_UNIT_STORAGE_KEY,
DISTANCE_UNIT_STORAGE_KEY,
TIME_FORMAT_STORAGE_KEY,
} from "./constants";

import {
AltitudeType,
AltitudeLevels,
HeightUnit,
SpeedUnit,
TemperatureUnit,
DistanceUnit,
TimeFormat,
} from "../rap/extra/settings/settingEnums";

const locationHashArray = document.location.hash
.replace(/#/, "")
.split(/&/)
.map((kv) => {
const [k, v] = kv.split(/=/);
return [k, decodeURI(v)] as const;
});

const locationHashMap: Map<string, string> = new Map(locationHashArray);

export function getAltitude() {
const value = locationHashMap.get(ALTITUDE_STORAGE_KEY) as AltitudeType;
if (
value !== AltitudeType.AGL &&
value !== AltitudeType.MSL &&
value !== AltitudeType.Pressure
)
return undefined;
return value;
}

export function getAltitudeLevels() {
const value = locationHashMap.get(
ALTITUDE_LEVELS_STORAGE_KEY,
) as AltitudeLevels;
if (value !== AltitudeLevels.Default && value !== AltitudeLevels.Normalized)
return undefined;
return value;
}

export function getHeightUnit() {
const value = locationHashMap.get(HEIGHT_UNIT_STORAGE_KEY) as HeightUnit;
if (value !== HeightUnit.Feet && value !== HeightUnit.Meters)
return undefined;
return value;
}

export function getSpeedUnit() {
const value = locationHashMap.get(SPEED_UNIT_STORAGE_KEY) as SpeedUnit;
if (
value !== SpeedUnit.KPH &&
value !== SpeedUnit.Knots &&
value !== SpeedUnit.MPH &&
value !== SpeedUnit.mps
)
return undefined;
return value;
}

export function getTemperatureUnit() {
const value = locationHashMap.get(
TEMPERATURE_UNIT_STORAGE_KEY,
) as TemperatureUnit;
if (value !== TemperatureUnit.Celsius && value !== TemperatureUnit.Fahrenheit)
return undefined;
return value;
}

export function getDistanceUnit() {
const value = locationHashMap.get(DISTANCE_UNIT_STORAGE_KEY) as DistanceUnit;
if (value !== DistanceUnit.Kilometers && value !== DistanceUnit.Miles)
return undefined;
return value;
}

export function getTimeFormat() {
const value = locationHashMap.get(TIME_FORMAT_STORAGE_KEY) as TimeFormat;
if (value !== TimeFormat.Twelve && value !== TimeFormat.TwentyFour)
return undefined;
return value;
}
36 changes: 19 additions & 17 deletions src/features/user/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,25 @@ export interface UserLocation {
isFallbackLabel?: boolean;
}

const LOCATIONS_STORAGE_KEY = "user-locations";
const ALTITUDE_STORAGE_KEY = "user-altitude";
const ALTITUDE_LEVELS_STORAGE_KEY = "user-altitude-levels";
const HEIGHT_UNIT_STORAGE_KEY = "user-height-unit";
const SPEED_UNIT_STORAGE_KEY = "user-speed-unit";
const TEMPERATURE_UNIT_STORAGE_KEY = "user-temperature-unit";
const DISTANCE_UNIT_STORAGE_KEY = "user-distance-unit";
const TIME_FORMAT_STORAGE_KEY = "user-time-format";
const DISCUSSION_LAST_VIEWED_STORAGE_KEY = "discussion-last-viewed";
const READ_ALERTS = "read-alerts";
const HIDDEN_ALERTS = "hidden-alerts";
const SWIPE_INERTIA_STORAGE_KEY = "swipe-inertia";
const G_AIRMET_READ_STORAGE_KEY = "g-airmet-read";
const LANGUAGE_STORAGE_KEY = "user-language";
const ADVANCED_STORAGE_KEY = "advanced-mode";
const MAX_LOCATIONS = 5;
const MAX_DISTANCE_MATCH = 1000; // meters
import {
LOCATIONS_STORAGE_KEY,
ALTITUDE_STORAGE_KEY,
ALTITUDE_LEVELS_STORAGE_KEY,
HEIGHT_UNIT_STORAGE_KEY,
SPEED_UNIT_STORAGE_KEY,
TEMPERATURE_UNIT_STORAGE_KEY,
DISTANCE_UNIT_STORAGE_KEY,
TIME_FORMAT_STORAGE_KEY,
DISCUSSION_LAST_VIEWED_STORAGE_KEY,
READ_ALERTS,
HIDDEN_ALERTS,
SWIPE_INERTIA_STORAGE_KEY,
G_AIRMET_READ_STORAGE_KEY,
LANGUAGE_STORAGE_KEY,
ADVANCED_STORAGE_KEY,
MAX_LOCATIONS,
MAX_DISTANCE_MATCH,
} from "./constants";

export function getLocations(): UserLocation[] {
const locations: UserLocation[] = JSON.parse(
Expand Down
17 changes: 10 additions & 7 deletions src/features/user/userSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import Geocode from "../../models/Geocode";
import { AppDispatch, RootState } from "../../store";
import { Alert } from "../alerts/alertsSlice";
import * as locationHash from "./locationHash";
import * as storage from "./storage";
import { UserLocation } from "./storage";
import { Languages } from "../../i18n";
Expand Down Expand Up @@ -37,13 +38,15 @@ interface UserState {
// Define the initial state using that type
const initialState: UserState = {
recentLocations: storage.getLocations(),
altitude: storage.getAltitude(),
altitudeLevels: storage.getAltitudeLevels(),
heightUnit: storage.getHeightUnit(),
speedUnit: storage.getSpeedUnit(),
temperatureUnit: storage.getTemperatureUnit(),
distanceUnit: storage.getDistanceUnit(),
timeFormat: storage.getTimeFormat(),
altitude: locationHash.getAltitude() ?? storage.getAltitude(),
altitudeLevels:
locationHash.getAltitudeLevels() ?? storage.getAltitudeLevels(),
heightUnit: locationHash.getHeightUnit() ?? storage.getHeightUnit(),
speedUnit: locationHash.getSpeedUnit() ?? storage.getSpeedUnit(),
temperatureUnit:
locationHash.getTemperatureUnit() ?? storage.getTemperatureUnit(),
distanceUnit: locationHash.getDistanceUnit() ?? storage.getDistanceUnit(),
timeFormat: locationHash.getTimeFormat() ?? storage.getTimeFormat(),
readAlerts: storage.getReadAlerts(),
hiddenAlerts: storage.getHiddenAlerts(),
swipeInertia: storage.getSwipeInertia(),
Expand Down

0 comments on commit ac15779

Please sign in to comment.