mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-07 16:19:01 +00:00
100 lines
3 KiB
TypeScript
100 lines
3 KiB
TypeScript
|
|
import { Box } from "@mui/material";
|
||
|
|
import { Text } from "@/components/ui/text";
|
||
|
|
import {
|
||
|
|
buildAddressQuery,
|
||
|
|
hasCompleteAddress,
|
||
|
|
mapsEmbedUrl,
|
||
|
|
type AddressParts,
|
||
|
|
} from "@/lib/address/vendor-address";
|
||
|
|
|
||
|
|
type AddressMapPreviewProps = {
|
||
|
|
/** Structured parts, as held by a form or a detail view. */
|
||
|
|
address?: Partial<AddressParts>;
|
||
|
|
/**
|
||
|
|
* An already-composed address line, for callers that hold saved data rather
|
||
|
|
* than live input — the Work Order vendor dialog gets one string from the
|
||
|
|
* vendor dropdown payload. Ignored when `address` is given.
|
||
|
|
*/
|
||
|
|
query?: string;
|
||
|
|
height?: number;
|
||
|
|
/**
|
||
|
|
* Render a compact accessible placeholder while the structured address is
|
||
|
|
* incomplete, instead of nothing. Meant for Add/Edit forms, where the empty
|
||
|
|
* state tells the dispatcher which parts the preview is still waiting on.
|
||
|
|
*/
|
||
|
|
placeholderWhenIncomplete?: boolean;
|
||
|
|
};
|
||
|
|
|
||
|
|
const INCOMPLETE_PLACEHOLDER_MESSAGE =
|
||
|
|
"Map preview appears once Street, City, and State are all filled.";
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Small inline map for a structured address.
|
||
|
|
*
|
||
|
|
* Uses Google's keyless `output=embed` form deliberately: SH-271 asks for a
|
||
|
|
* preview with no API key, so there is no Maps JavaScript API, no Places
|
||
|
|
* request and no billing account behind this.
|
||
|
|
*
|
||
|
|
* Structured input renders nothing until Street, City and State are all
|
||
|
|
* present — a preview of a half-typed address points somewhere misleading,
|
||
|
|
* which is worse than no map. Add/Edit forms opt into a compact placeholder
|
||
|
|
* for that incomplete state; a pre-composed saved line is map-only and renders
|
||
|
|
* only when non-empty.
|
||
|
|
*/
|
||
|
|
export function AddressMapPreview({
|
||
|
|
address,
|
||
|
|
query: rawQuery,
|
||
|
|
height = 160,
|
||
|
|
placeholderWhenIncomplete = false,
|
||
|
|
}: AddressMapPreviewProps) {
|
||
|
|
// Structured input is held to the completeness rule; a pre-composed line is
|
||
|
|
// saved data and only has to be non-empty.
|
||
|
|
const query = address ? buildAddressQuery(address) : (rawQuery ?? "").trim();
|
||
|
|
const complete = address ? hasCompleteAddress(address) : Boolean(query);
|
||
|
|
|
||
|
|
if (!complete) {
|
||
|
|
if (!(address != null && placeholderWhenIncomplete)) return null;
|
||
|
|
return (
|
||
|
|
<Box
|
||
|
|
role="status"
|
||
|
|
sx={{
|
||
|
|
borderRadius: 1,
|
||
|
|
border: "1px dashed",
|
||
|
|
borderColor: "divider",
|
||
|
|
minHeight: 56,
|
||
|
|
display: "flex",
|
||
|
|
alignItems: "center",
|
||
|
|
justifyContent: "center",
|
||
|
|
px: 1.5,
|
||
|
|
py: 1,
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<Text variant="caption" tone="muted" sx={{ textAlign: "center" }}>
|
||
|
|
{INCOMPLETE_PLACEHOLDER_MESSAGE}
|
||
|
|
</Text>
|
||
|
|
</Box>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Box
|
||
|
|
sx={{
|
||
|
|
borderRadius: 1,
|
||
|
|
overflow: "hidden",
|
||
|
|
border: 1,
|
||
|
|
borderColor: "divider",
|
||
|
|
lineHeight: 0,
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<Box
|
||
|
|
component="iframe"
|
||
|
|
title={`Map of ${query}`}
|
||
|
|
src={mapsEmbedUrl({ street: query })}
|
||
|
|
loading="lazy"
|
||
|
|
referrerPolicy="no-referrer-when-downgrade"
|
||
|
|
sx={{ display: "block", width: "100%", height, border: 0 }}
|
||
|
|
/>
|
||
|
|
</Box>
|
||
|
|
);
|
||
|
|
}
|