import { useAuthedImage } from '../hooks.js' // One picture from the API, however this deployment stores them. // // Two shapes arrive here and they need different handling, which is exactly // why it is one component rather than an repeated on each screen: // // * A presigned link to object storage carries its own signature, so a plain // loads it. // * A picture this server holds itself - for a deployment with no bucket - // is served from an endpoint that requires the session. An cannot // send an Authorization header, so it has to be fetched and handed over as // an object URL. Minting an unauthenticated link instead would put a // photograph of somebody's shop floor, or of a customer, behind no session // at all, which is the thing that path exists to avoid. // // Which one it is comes from the API's own `auth` flag, not from the shape of // the URL. Guessing by whether it starts with "/" is right today and stops // being right the first time object storage is served from this same host - // and the failure then is a photograph that silently will not load. export default function Shot({ image, url, alt }) { // `image` is the whole object from the API; `url` is the older call shape, // kept working so a screen that has not been updated still renders. The // fallback heuristic applies only when nothing told us. const src0 = image ? image.url : url // Either signal is enough, and that is not belt-and-braces. A RELATIVE url is // served by this server and always needs the session - there is no such thing // as a public one - so it is sufficient on its own, and a caller that rebuilds // an image object and loses `auth` cannot turn a working picture into a broken // one. (It did exactly that once: Sites.jsx returned `{url, at}` from its // snapshot picker, the flag went missing, and every shop card showed a broken // image.) The FLAG is what adds the case the URL cannot express: an absolute // link that still needs a bearer, which happens the first time object storage // is served from this same host. const needsAuth = (image && !!image.auth) || (typeof src0 === 'string' && src0.startsWith('/')) // Hooks cannot be called conditionally, so this always runs and simply has // nothing to do when the URL is already usable. const fetched = useAuthedImage(needsAuth ? src0 : null) const src = needsAuth ? fetched : src0 if (!src) return null return {alt} }