diff --git a/src/api/PizzaApi.ts b/src/api/PizzaApi.ts index 89420302..b3ebe1d2 100644 --- a/src/api/PizzaApi.ts +++ b/src/api/PizzaApi.ts @@ -58,7 +58,7 @@ class PizzaApi { } public async getOrder(id: OrderId, errorHandler?: (error: ApiError) => void): Promise { - return this.handleResponse(await baseFetch(`/order/${id}`), errorHandler); + return this.handleResponse(await baseFetch(`/orders/${id}`), errorHandler); } public async getOrders(page: number = 0, limit: number = 100, errorHandler?: (error: ApiError) => void): Promise { diff --git a/src/components.d.ts b/src/components.d.ts index 3a79432d..67b442cf 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -91,6 +91,7 @@ export namespace Components { } interface UiGeoMap { "center"?: google.maps.LatLngLiteral; + "currentAddress"?: string; "deliveries"?: { coords: google.maps.LatLngLiteral; id: LocationId }[]; "trucks"?: { coords: google.maps.LatLngLiteral; id: LocationId }[]; "zoom"?: number; @@ -452,6 +453,7 @@ declare namespace LocalJSX { } interface UiGeoMap { "center"?: google.maps.LatLngLiteral; + "currentAddress"?: string; "deliveries"?: { coords: google.maps.LatLngLiteral; id: LocationId }[]; "onMarkerSelected"?: (event: CustomEvent<{ type: "pizza" | "truck"; diff --git a/src/components/app-root/app-root.tsx b/src/components/app-root/app-root.tsx index c9186453..5755897a 100644 --- a/src/components/app-root/app-root.tsx +++ b/src/components/app-root/app-root.tsx @@ -72,7 +72,7 @@ export class AppRoot { - + diff --git a/src/components/page-activity/page-activity.tsx b/src/components/page-activity/page-activity.tsx index ce5413cf..10f10da6 100644 --- a/src/components/page-activity/page-activity.tsx +++ b/src/components/page-activity/page-activity.tsx @@ -1,7 +1,7 @@ import { Component, h, Host, State } from "@stencil/core"; import { OrderDetails, PizzaApi } from "../../api"; -import { scrollPageToTop } from "../../util"; +import { locationURL, scrollPageToTop } from "../../util"; @Component({ tag: "page-activity", @@ -41,11 +41,11 @@ export class PageActivity {

{date}

- {orders.map(({ id, createdAt, orderType, pizzas, location: { fullAddress }, reports }: OrderDetails) => ( + {orders.map(({ id, createdAt, orderType, pizzas, location, reports }: OrderDetails) => (
  • {pizzas} {orderType} ordered at {new Date(createdAt).toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" })} for{" "} - {fullAddress} + {location.fullAddress}
      {reports.map(({ reportURL, createdAt: reportCreatedAt, waitTime }) => ( diff --git a/src/components/page-deliveries/page-deliveries.scss b/src/components/page-deliveries/page-deliveries.scss index 477405df..02d86fd5 100644 --- a/src/components/page-deliveries/page-deliveries.scss +++ b/src/components/page-deliveries/page-deliveries.scss @@ -42,34 +42,6 @@ page-deliveries { cursor: pointer; } - hr.heavy { - width: 100%; - background-color: $red; - height: 8px; - margin: 0; - } - - #deliveries-map-container { - background-color: $gray1; - width: 100%; - height: 300px; - - @media ($tablet) { - height: 420px; - } - - &.is-single-location { - height: 200px; - } - } - - .now-feeding { - padding: 0.5em 0 0.5em 1.5em; - font-size: 0.8em; - font-weight: 600; - background-color: $white; - } - .food-choices { font-size: 0.9em; font-weight: 600; diff --git a/src/components/page-deliveries/page-deliveries.tsx b/src/components/page-deliveries/page-deliveries.tsx index 217004ca..21335b1f 100644 --- a/src/components/page-deliveries/page-deliveries.tsx +++ b/src/components/page-deliveries/page-deliveries.tsx @@ -1,10 +1,8 @@ import { Build, Component, Fragment, FunctionalComponent, h, Host, Listen, Prop, State, Watch } from "@stencil/core"; import { MatchResults, RouterHistory } from "@stencil/router"; -// @ts-ignore -import {} from "googlemaps"; import { LocationInfo, LocationStatus, OrderDetails, OrderInfo, OrderTypes, PizzaApi, TruckDetails, TruckInfo } from "../../api"; -import { scrollPageToTop } from "../../util"; +import { formatDateTime, formatTime, scrollPageToTop } from "../../util"; import { UiGeoMap } from "../ui-geo-map/ui-geo-map"; enum FoodChoice { @@ -15,10 +13,6 @@ enum FoodChoice { type OrderOrTruckItem = { type: "pizza"; data: OrderDetails | null } | { type: "truck"; data: TruckDetails | null }; -const formatTime = (date: Date) => date.toLocaleTimeString([], { hour: "numeric", minute: "2-digit", timeZoneName: "short" }); - -const formatDate = (date: Date) => date.toLocaleDateString([], { day: "2-digit", month: "2-digit" }); - const ReportLink = () => Make a report; const FoodChoices: FunctionalComponent<{ @@ -46,7 +40,7 @@ const OrderDetailDisplay: FunctionalComponent<{ x.location.fullAddress} />
      - `${x.quantity} ${x.orderType} at ${formatDate(x.createdAt)} ${formatTime(x.createdAt)}`} /> + `${x.quantity} ${x.orderType} at ${formatDateTime(x.createdAt)}`} />
      ); @@ -62,10 +56,7 @@ const OrderInfoDisplay: FunctionalComponent<{ `${x.quantity} ${x.orderType} en route`} />
      - `${formatDate(x.createdAt)} ${formatTime(x.createdAt)}${reportCount > 0 ? ` • ${reportCount} report${reportCount === 1 ? "" : "s"}` : ""}`} - /> + `${formatDateTime(x.createdAt)}${reportCount > 0 ? ` • ${reportCount} report${reportCount === 1 ? "" : "s"}` : ""}`} />
      ); @@ -80,7 +71,7 @@ const TruckInfoDisplay: FunctionalComponent<{ x.location.fullAddress} />
      - `Food truck on location since ${formatDate(x.createdAt)} ${formatTime(x.createdAt)}`} /> + `Food truck on location since ${formatDateTime(x.createdAt)}`} />
      ); @@ -104,9 +95,6 @@ const OrderAndTruckInfoList: FunctionalComponent<{ ), ); -const DEFAULT_ZOOM = 4; -const SELECTED_LOCATION_ZOOM = 15; - @Component({ tag: "page-deliveries", styleUrl: "page-deliveries.scss", @@ -117,21 +105,20 @@ export class PageDeliveries { @Prop() public match!: MatchResults; @State() private selectedAddress?: string; + @State() private selectedLocation?: LocationStatus; + @State() private selectedOrder?: OrderInfo; /** * Watched and used to re-center the map */ - // @ts-ignore @State() private mapCenterPoint: { lat: number; lng: number }; @State() private selectedFood: FoodChoice; - @State() private selectedLocation?: LocationStatus; - @State() private selectedOrder?: OrderInfo; @State() private recentOrders?: OrderDetails[]; @State() private recentTrucks?: TruckInfo[]; @State() private mapZoom: number; constructor() { this.selectedFood = FoodChoice.all; - this.mapZoom = DEFAULT_ZOOM; + this.mapZoom = UiGeoMap.DEFAULT_ZOOM; this.mapCenterPoint = UiGeoMap.US_CENTER; } @@ -161,32 +148,19 @@ export class PageDeliveries { } } - /* - @Watch( "selectedFood" ) - public selectedFoodChanged( filter: FoodChoice ) { - const val = filter === FoodChoice.all - ? "" - : Object.keys( FoodChoice ).find( k => ( FoodChoice as any )[k] === filter ) + ""; - if( window.location.hash !== val ) { - window.location.hash = val; - } - } - */ - /** * Lookup location info when the selected address value changes */ @Watch("selectedAddress") public selectedAddressChanged(newAddress?: string, oldAddress?: string) { - const ownPathFragment = this.history.location.pathname.split("/").filter(x => x !== "")[0]; - if (newAddress == null && oldAddress != null) { - const path = `/${ownPathFragment}`; + if (newAddress === undefined && oldAddress != null) { + const path = `/deliveries`; this.selectedLocation = undefined; if (this.history.location.pathname !== path) { this.history.push(path, {}); } } else if (newAddress != null && newAddress !== oldAddress) { - const path = `/${ownPathFragment}/${newAddress}`; + const path = `/deliveries/${newAddress.replace(/\s/g, "+")}`; if (this.history.location.pathname !== path) { this.history.push(path, {}); } @@ -213,9 +187,9 @@ export class PageDeliveries { @Watch("mapCenterPoint") public mapCenterPointChanged(coords?: { lat: number; lng: number }) { if (coords?.lat === UiGeoMap.US_CENTER.lat) { - this.mapZoom = DEFAULT_ZOOM; + this.mapZoom = UiGeoMap.DEFAULT_ZOOM; } else { - this.mapZoom = SELECTED_LOCATION_ZOOM; + this.mapZoom = UiGeoMap.SELECTED_LOCATION_ZOOM; } scrollPageToTop(); } @@ -319,15 +293,14 @@ export class PageDeliveries { )} (this.selectedFood = x)} /> -
      -
      Now feeding{nowFeeding || " American voters"}
      ({ + ? this.recentOrders?.slice(0, 100).map(x => ({ coords: { lat: parseFloat(x.location.lat), lng: parseFloat(x.location.lng), @@ -338,7 +311,7 @@ export class PageDeliveries { } trucks={ selectedFood === FoodChoice.all || selectedFood === FoodChoice.trucks - ? this.recentTrucks?.slice(0, 20).map(x => ({ + ? this.recentTrucks?.slice(0, 50).map(x => ({ coords: { lat: parseFloat(x.location.lat), lng: parseFloat(x.location.lng), @@ -365,14 +338,14 @@ export class PageDeliveries {
      -

      Current Deliveries

      +

      Recent Deliveries

      {selectedLocation != null && selectedFood === FoodChoice.trucks && locationItems.length < 1 ? (

      There are no food trucks currently at this location.

      - ) : selectedLocation != null && ((selectedFood === FoodChoice.pizza && locationItems.length < 1) || selectedLocation.notFound === true) ? ( + ) : selectedLocation != null && (locationItems.length < 1 || selectedLocation.notFound === true) ? (

      There are no reports of lines at this location.
      @@ -433,9 +406,7 @@ export class PageDeliveries {

      {selectedOrder!.pizzas} Pizzas

      - - {formatDate(selectedOrder!.createdAt)}, {formatTime(selectedOrder!.createdAt)} - + {formatDateTime(selectedOrder!.createdAt)}

      From {selectedOrder!.restaurant}

        @@ -470,8 +441,9 @@ export class PageDeliveries { }; } - private setAddressFromUrl(match: MatchResults) { - const location = match.params.location; + private async setAddressFromUrl(match: MatchResults) { + const location = match.params?.location?.replace(/\+/g, " "); + if (location !== this.selectedAddress) { this.selectedAddress = location; // TODO: Lookup address lat/lng from selectedAddress diff --git a/src/components/page-home/Deliveries.tsx b/src/components/page-home/Deliveries.tsx index 80559a4e..6b497da5 100644 --- a/src/components/page-home/Deliveries.tsx +++ b/src/components/page-home/Deliveries.tsx @@ -1,29 +1,23 @@ import { h } from "@stencil/core"; import { OrderDetails } from "../../api"; +import { locationURL } from "../../util"; +import { formatDateTime } from "../../util"; const capitalize = (word: string): String => `${word.slice(0, 1).toUpperCase()}${word.slice(1, word.length)}`; -const formatDate = (date: Date): String => { - const day = date.getDate(); - const month = date.getMonth() + 1; - const hours = date.getHours() > 12 ? date.getHours() - 12 : date.getHours(); - const minutes = date.getMinutes(); - const meridian = date.getHours() > 12 ? "pm" : "am"; - - return `${day}/${month} ${hours}:${minutes} ${meridian}`; -}; - const Delivery = ({ order }: { order: OrderDetails }) => (
        -
        +
        {order.quantity} {capitalize(order.orderType)}
        - {formatDate(order.createdAt)} + {formatDateTime(order.createdAt)}

        - {order.location.address} in -
        - {order.location.city}, {order.location.state} + + {order.location.address} in +
        + {order.location.city}, {order.location.state} +

        ); @@ -36,6 +30,10 @@ const Deliveries = ({ orders }: { orders?: OrderDetails[] }) => ( ))}
      +
      + + See more deliveries +
      ); diff --git a/src/components/page-home/page-home.scss b/src/components/page-home/page-home.scss index 5752847b..a3fd8fc6 100644 --- a/src/components/page-home/page-home.scss +++ b/src/components/page-home/page-home.scss @@ -232,7 +232,7 @@ page-home { .deliveries-wrapper { overflow-y: scroll; - height: 100%; + height: 93%; } @media ($under-tweet) { @@ -250,7 +250,6 @@ page-home { border-bottom: 1px solid $gray2; margin: 10px 0; padding: 4px 0; - h5 { margin: 0; line-height: 0.5rem; @@ -263,6 +262,10 @@ page-home { p { color: $gray4; font-size: 0.75rem; + font-weight: normal; + a { + color: $gray4; + } } } } diff --git a/src/components/page-home/page-home.tsx b/src/components/page-home/page-home.tsx index 54c03504..b0450745 100644 --- a/src/components/page-home/page-home.tsx +++ b/src/components/page-home/page-home.tsx @@ -1,4 +1,4 @@ -import { Build, Component, h, Prop, State } from "@stencil/core"; +import { Component, h, Prop, State } from "@stencil/core"; import { RouterHistory } from "@stencil/router"; import { OrderDetails, PizzaApi, PizzaTotals } from "../../api"; @@ -20,10 +20,8 @@ export class PageHome { public async componentWillLoad() { document.title = `Home | Pizza to the Polls`; - if (Build.isBrowser) { - PizzaApi.getTotals().then(totals => (this.totals = totals)); - PizzaApi.getOrders(0, 20).then(({ results }) => (this.orders = results)); - } + PizzaApi.getTotals().then(totals => (this.totals = totals)); + PizzaApi.getOrders(0, 20).then(({ results }) => (this.orders = results)); } public render() { diff --git a/src/components/ui-geo-map/ui-geo-map.scss b/src/components/ui-geo-map/ui-geo-map.scss index 044cb4f6..efb1964b 100644 --- a/src/components/ui-geo-map/ui-geo-map.scss +++ b/src/components/ui-geo-map/ui-geo-map.scss @@ -5,4 +5,33 @@ width: 100%; height: 100%; } + + hr.heavy { + width: 100%; + background-color: $red; + height: 8px; + margin: 0; + border: none; + } + + #deliveries-map-container { + background-color: $gray1; + width: 100%; + height: 300px; + + @media ($tablet) { + height: 420px; + } + + &.is-single-location { + height: 200px; + } + } + + .now-feeding { + padding: 0.5em 0 0.5em 1.5em; + font-size: 0.8em; + font-weight: 600; + background-color: $white; + } } diff --git a/src/components/ui-geo-map/ui-geo-map.tsx b/src/components/ui-geo-map/ui-geo-map.tsx index 8aeaa277..2390a791 100644 --- a/src/components/ui-geo-map/ui-geo-map.tsx +++ b/src/components/ui-geo-map/ui-geo-map.tsx @@ -13,12 +13,14 @@ export class UiGeoMap { public static readonly US_CAPITOL: google.maps.LatLngLiteral = { lat: 38.8899, lng: -77.0091 }; public static readonly US_CENTER: google.maps.LatLngLiteral = { lat: 39.8283, lng: -98.5795 }; public static readonly DEFAULT_CENTER: google.maps.LatLngLiteral = UiGeoMap.US_CENTER; - public static readonly DEFAULT_ZOOM = 16; + public static readonly DEFAULT_ZOOM = 4; + public static readonly SELECTED_LOCATION_ZOOM = 15; @Prop() public center?: google.maps.LatLngLiteral; @Prop() public zoom?: number; @Prop() public deliveries?: { coords: google.maps.LatLngLiteral; id: LocationId }[]; @Prop() public trucks?: { coords: google.maps.LatLngLiteral; id: LocationId }[]; + @Prop() public currentAddress?: string; @Event({ cancelable: false }) public markerSelected!: EventEmitter<{ type: "pizza" | "truck"; @@ -75,7 +77,15 @@ export class UiGeoMap { } public render() { - return
      (this.mapElement = x)}>
      ; + return ( +
      +
      +
      Now feeding {this.currentAddress || "American voters"}
      +
      +
      (this.mapElement = x)}>
      +
      +
      + ); } private modifyMarkers(type: "pizza" | "truck", existingMarkers: google.maps.Marker[], newMarkers: { coords: google.maps.LatLngLiteral; id: LocationId }[]) { diff --git a/src/components/ui-main-content/ui-main-content.scss b/src/components/ui-main-content/ui-main-content.scss index 4f83c6e5..7e67d037 100644 --- a/src/components/ui-main-content/ui-main-content.scss +++ b/src/components/ui-main-content/ui-main-content.scss @@ -1,6 +1,6 @@ ui-main-content { .background { - background-image: url("images/redpepper.png"), url("images/pizza-star.svg"), url("images/basil.png"), url("images/pizza-yellow.svg"); + background-image: url("/images/redpepper.png"), url("/images/pizza-star.svg"), url("/images/basil.png"), url("/images/pizza-yellow.svg"); background-repeat: no-repeat; background-position: 2% 27.4rem, -3% 38rem, 98% 15rem, 102% 25rem; background-size: 3rem, 8rem, 4rem, 10rem; @@ -24,7 +24,7 @@ ui-main-content { &:before { position: absolute; content: ""; - background-image: url(images/pizza-pink.svg); + background-image: url("/images/pizza-pink.svg"); width: 10rem; height: 10rem; background-size: contain; diff --git a/src/util/format.ts b/src/util/format.ts new file mode 100644 index 00000000..f4bb92b2 --- /dev/null +++ b/src/util/format.ts @@ -0,0 +1,5 @@ +export const formatTime = (date: Date): string => date.toLocaleTimeString([], { hour: "numeric", minute: "2-digit", timeZoneName: "short" }); + +export const formatDate = (date: Date): string => date.toLocaleDateString([], { day: "2-digit", month: "2-digit" }); + +export const formatDateTime = (date: Date): string => `${formatDate(date)} ${formatTime(date)}`; diff --git a/src/util/index.ts b/src/util/index.ts index 4d650863..d876d559 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -1,3 +1,5 @@ export { default as debounce } from "./debounce"; export { default as scrollPageToTop } from "./scrollPageToTop"; export { default as toQueryString } from "./toQueryString"; +export { orderURL, locationURL } from "./urls"; +export { formatDateTime, formatTime } from "./format"; diff --git a/src/util/urls.ts b/src/util/urls.ts new file mode 100644 index 00000000..8617a565 --- /dev/null +++ b/src/util/urls.ts @@ -0,0 +1,5 @@ +import { LocationInfo, OrderDetails } from "../api"; + +export const orderURL = (order: OrderDetails): string => `${locationURL(order.location)}/${order.id}`; + +export const locationURL = (location: LocationInfo): string => `/deliveries/${location.fullAddress.replace(/\s/g, "+")}`;