diff --git a/packages/ui/src/components/busSelector.tsx b/packages/ui/src/components/busSelector.tsx index b607682..0c15890 100644 --- a/packages/ui/src/components/busSelector.tsx +++ b/packages/ui/src/components/busSelector.tsx @@ -1,5 +1,5 @@ import { useState, useCallback, useMemo, memo, useEffect, useRef } from 'react' -import { useQuery } from '@tanstack/react-query' +import { useQuery, useIsFetching } from '@tanstack/react-query' import { useNavigate, generatePath } from 'react-router-dom' import { latLng, latLngBounds } from 'leaflet' import styled from 'styled-components' @@ -43,6 +43,8 @@ const BusSelector = memo(function BusSelector({ agencies }: BusSelectorProps) { const [routeName, setRouteName] = useState() const { dispatch, agency, route, direction, stop } = useGlobals() const vehiclesDispatch = useVehiclesDispatch() + const vehicleFetches = useIsFetching({ queryKey: ['vehicles'] }) + const routeVehiclesLoaded = useRef(false) const stops = useMemo(() => { if (direction && route) { return route.stops.filter(({ id }) => direction.stops.includes(id)) @@ -57,7 +59,7 @@ const BusSelector = memo(function BusSelector({ agencies }: BusSelectorProps) { const { data: routes, error: routesError, - isLoading: isRoutesLoading + isFetching: isRoutesFetching } = useQuery({ queryKey: ['routes', agency?.id], queryFn: () => getAllRoutes(agency?.id), @@ -67,7 +69,7 @@ const BusSelector = memo(function BusSelector({ agencies }: BusSelectorProps) { const { data: routeConfig, error: routeError, - isLoading: isRouteLoading + isFetching: isRouteFetching } = useQuery({ /** * Use two attributes from a route to prevent collisions across agencies. @@ -156,7 +158,9 @@ const BusSelector = memo(function BusSelector({ agencies }: BusSelectorProps) { } }, [navigate, dispatch, vehiclesDispatch, agency, route, direction]) const error = getFirstDataError([routesError, routeError]) - const isLoading = isRoutesLoading || isRouteLoading + const isFetching = isRoutesFetching || isRouteFetching + const isPageLoading = + isFetching || Boolean(!routeVehiclesLoaded.current && vehicleFetches) /** * Update page title and description. @@ -286,8 +290,23 @@ const BusSelector = memo(function BusSelector({ agencies }: BusSelectorProps) { } }, [dispatch, homeStop, agencies, agency, routeName, routes, route, direction, stop]) + /** + * These effects are so that the loader only + * renders for the first load of vehicles + * when the route changes. + */ + useEffect(() => { + routeVehiclesLoaded.current = false + }, [route]) + + useEffect(() => { + if (!vehicleFetches && !routeVehiclesLoaded.current) { + routeVehiclesLoaded.current = true + } + }, [vehicleFetches]) + return ( - + {error instanceof Error && }
{ @@ -297,26 +316,26 @@ const BusSelector = memo(function BusSelector({ agencies }: BusSelectorProps) { agencies={agencies} selected={agency} onSelect={onSelectAgency} - isDisabled={isLoading} + isDisabled={isFetching} />
diff --git a/packages/ui/src/components/dots.tsx b/packages/ui/src/components/dots.tsx new file mode 100644 index 0000000..663da7e --- /dev/null +++ b/packages/ui/src/components/dots.tsx @@ -0,0 +1,12 @@ +import { Loading } from '@busmap/components/loading' +import { PB90T, PB20T } from '@busmap/components/colors' + +import { useTheme } from '@module/settings/contexts/theme.js' + +const Dots = () => { + const { mode } = useTheme() + + return +} + +export { Dots } diff --git a/packages/ui/src/components/loading.tsx b/packages/ui/src/components/loading.tsx index 9d230c0..6f27c5f 100644 --- a/packages/ui/src/components/loading.tsx +++ b/packages/ui/src/components/loading.tsx @@ -1,8 +1,6 @@ import styled from 'styled-components' -import { Loading as Dots } from '@busmap/components/loading' -import { PB20T, PB90T } from '@busmap/components/colors' -import { useTheme } from '../modules/settings/contexts/theme.js' +import { Dots } from './dots.js' import type { FC } from 'react' @@ -24,12 +22,10 @@ const Text = styled.p` font-size: 1rem; ` const Loading: FC = ({ text, useIcon = true }) => { - const { mode } = useTheme() - return ( - {text} {useIcon && } + {text} {useIcon && } ) diff --git a/packages/ui/src/components/page.tsx b/packages/ui/src/components/page.tsx index 9ef0dfe..4960e04 100644 --- a/packages/ui/src/components/page.tsx +++ b/packages/ui/src/components/page.tsx @@ -1,10 +1,13 @@ import styled from 'styled-components' +import { Dots } from './dots.js' + import type { FC, ReactNode } from 'react' interface PageProps { title: string className?: string + loading?: boolean children: ReactNode } @@ -23,10 +26,13 @@ const Section = styled.section` line-height: 1.25; } ` -const Page: FC = ({ title, children, className }) => { +const Page: FC = ({ title, children, className, loading = false }) => { return (
-

{title}

+

+ {title} + {loading && } +

{children}
) diff --git a/packages/ui/src/components/profile.tsx b/packages/ui/src/components/profile.tsx index b6e29f5..ee70d42 100644 --- a/packages/ui/src/components/profile.tsx +++ b/packages/ui/src/components/profile.tsx @@ -4,7 +4,6 @@ import { toast } from '@busmap/components/toast' import { Button } from '@busmap/components/button' import { SignOut } from '@busmap/components/icons/signOut' import { PB80T, PB20T, PB90T } from '@busmap/components/colors' -import { Loading } from '@busmap/components/loading' import { logout } from '@core/api/authn.js' import { useGlobals } from '@core/globals.js' @@ -12,6 +11,7 @@ import { useStorageDispatch } from '@core/contexts/storage.js' import { useTheme } from '@module/settings/contexts/theme.js' import { Page } from './page.js' +import { Dots } from './dots.js' import type { FC } from 'react' import type { Mode } from '@busmap/common/types/settings' @@ -151,7 +151,7 @@ const Profile: FC = () => {
{loading ? (

- Signing you out + Signing you out

) : ( diff --git a/packages/ui/src/components/signIn.tsx b/packages/ui/src/components/signIn.tsx index 89e26ca..b4da071 100644 --- a/packages/ui/src/components/signIn.tsx +++ b/packages/ui/src/components/signIn.tsx @@ -1,17 +1,15 @@ import { useEffect, useRef, useState } from 'react' import styled from 'styled-components' import { toast } from '@busmap/components/toast' -import { Loading } from '@busmap/components/loading' -import { PB20T, PB90T } from '@busmap/components/colors' import { login } from '@core/api/authn.js' import { useGlobals } from '@core/globals.js' import { useStorageDispatch } from '@core/contexts/storage.js' -import { useTheme } from '@module/settings/contexts/theme.js' import { MAX_USER_FAVORITES } from '@module/favorites/common.js' import { get as getFavorites } from '@module/favorites/api/get.js' import { Page } from './page.js' +import { Dots } from './dots.js' import type { FC } from 'react' import type { RiderFavoriteItem } from '@busmap/common/types/favorites' @@ -22,7 +20,6 @@ const Note = styled.em` const SignIn: FC = () => { const ref = useRef(null) const { dispatch } = useGlobals() - const { mode } = useTheme() const [riderFavorites, setRiderFavorites] = useState() const [loading, setLoading] = useState(false) const storageDispatch = useStorageDispatch() @@ -81,7 +78,7 @@ const SignIn: FC = () => { {loading ? (

- Signing you in + Signing you in

) : ( <> diff --git a/packages/web/default.dev.conf b/packages/web/default.dev.conf index 4680911..4baa153 100644 --- a/packages/web/default.dev.conf +++ b/packages/web/default.dev.conf @@ -18,8 +18,6 @@ include /etc/nginx/conf.d/core/compression.conf; location / { - resolver 8.8.8.8 valid=30s; - proxy_pass http://dev_server; proxy_http_version 1.1; proxy_set_header Host $host; diff --git a/packages/web/templates/default.conf.template b/packages/web/templates/default.conf.template index edeb59a..7e11078 100644 --- a/packages/web/templates/default.conf.template +++ b/packages/web/templates/default.conf.template @@ -1,6 +1,4 @@ -# Configuration to stage a production build locally. -# Known differences: -# - TODO (when they arise) +# Configuration to stage a production build. server { # Redirect server configuration @@ -14,6 +12,7 @@ server { server { listen 443 ssl; + listen [::]:443 ssl; http2 on; server_name ${SERVER_NAME}; root /var/www/${HOST_NAME}; @@ -22,10 +21,13 @@ server { include /etc/nginx/conf.d/core/ssl.conf; include /etc/nginx/conf.d/core/compression.conf; - location / { - resolver 8.8.8.8 valid=30s; + location = /healthcheck { + add_header Content-Type "application/json"; + return 200 '{"status": "OK"}'; + } - location ~ /(authn|restbus|rider|favorite) { + location / { + location ~ /(authn|restbus|rider|favorite|health) { access_log /var/log/nginx/api.log api; proxy_pass http://api_server; # Allow keepalive to work with the upstream