refactor: implement getStorageUrl utility for consistent storage URL generation
This commit is contained in:
parent
4229d44c2f
commit
830b89d4b1
15 changed files with 186 additions and 27 deletions
|
|
@ -65,7 +65,7 @@ const OnboardingServizio = ({
|
|||
alt={`Annuncio image - ${annuncio.codice}`}
|
||||
className="block w-[240px] rounded-[4px] object-cover object-center"
|
||||
height="140px"
|
||||
src={`${env.BASE_URL}/storage-api/get/${annuncio.immagine}?image=true`}
|
||||
src={`${env.BASE_URL}/storage-api/get/${annuncio.immagine}?media=image`}
|
||||
width="100%"
|
||||
/>
|
||||
</Row>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import dynamic from "next/dynamic";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { LoadingPage } from "~/components/loading";
|
||||
import { getStorageUrl } from "~/lib/storage_utils";
|
||||
import { cn } from "~/lib/utils";
|
||||
import type { FileMetadata } from "~/server/services/storage.service";
|
||||
|
||||
|
|
@ -50,7 +51,10 @@ export const AllegatoIframe = ({
|
|||
}
|
||||
};
|
||||
|
||||
const requestUrl = `/storage-api/get/${allegato.id}?mode=inline`;
|
||||
const requestUrl = getStorageUrl({
|
||||
storageId: allegato.id,
|
||||
params: { mode: "inline" },
|
||||
});
|
||||
// For PDF on iOS, provide download link instead
|
||||
if (isPDF && (isIOS || isMobile)) {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import {
|
|||
import { LoadingPage } from "~/components/loading";
|
||||
import { Status500 } from "~/components/status-page";
|
||||
import { handleConsegna } from "~/lib/annuncio_details";
|
||||
import { getStorageUrl } from "~/lib/storage_utils";
|
||||
import { formatCurrency } from "~/lib/utils";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
import { useRicerca } from "~/providers/RicercaProvider";
|
||||
|
|
@ -123,7 +124,13 @@ const SelectedComp = memo(
|
|||
alt="a"
|
||||
className="size-24 rounded-md object-cover sm:size-40"
|
||||
height={500}
|
||||
src={`/storage-api/get/${selected.images[0].img}?image=true&cachekey=${selected?.toString()}`}
|
||||
src={getStorageUrl({
|
||||
storageId: selected.images[0].img,
|
||||
params: {
|
||||
media: "image",
|
||||
cacheKey: selected.media_updated_at?.toISOString(),
|
||||
},
|
||||
})}
|
||||
width={500}
|
||||
/>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {
|
|||
DialogTitle,
|
||||
} from "~/components/ui/dialog";
|
||||
import { camereTesti, handleConsegna } from "~/lib/annuncio_details";
|
||||
import { getStorageUrl } from "~/lib/storage_utils";
|
||||
import { cn, formatCurrency } from "~/lib/utils";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
import type { ImagesRefs } from "~/schemas/public/ImagesRefs";
|
||||
|
|
@ -217,14 +218,26 @@ export const CardAnnuncio = ({
|
|||
<CarouselItem key={`${img.img}key`}>
|
||||
<ImageFlbk
|
||||
alt={t.card.alt_immagine}
|
||||
blurDataURL={`/storage-api/get/${img.thumb}?image=true&cachekey=${media_updated_at?.toString()}`}
|
||||
blurDataURL={getStorageUrl({
|
||||
storageId: img.thumb,
|
||||
params: {
|
||||
cacheKey: media_updated_at?.toISOString(),
|
||||
media: "image",
|
||||
},
|
||||
})}
|
||||
className={cn(
|
||||
"h-64 w-full bg-[#e6e9ec] object-cover",
|
||||
(stato === "Trattativa" || homepage) && "rounded-[7px]",
|
||||
)}
|
||||
height={1080}
|
||||
priority={idx === 0}
|
||||
src={`/storage-api/get/${img.img}?image=true&cachekey=${media_updated_at?.toString()}`}
|
||||
src={getStorageUrl({
|
||||
storageId: img.img,
|
||||
params: {
|
||||
cacheKey: media_updated_at?.toISOString(),
|
||||
media: "image",
|
||||
},
|
||||
})}
|
||||
width={1920}
|
||||
/>
|
||||
</CarouselItem>
|
||||
|
|
@ -241,9 +254,21 @@ export const CardAnnuncio = ({
|
|||
>
|
||||
<VideoPlayer
|
||||
className="h-64 object-cover"
|
||||
coverImage={`/storage-api/get/${video.thumb}?image=true&cachekey=${media_updated_at?.toString()}`}
|
||||
coverImage={getStorageUrl({
|
||||
storageId: video.thumb,
|
||||
params: {
|
||||
cacheKey: media_updated_at?.toISOString(),
|
||||
media: "image",
|
||||
},
|
||||
})}
|
||||
key={`videoplayer-${video}`}
|
||||
videoSrc={`/storage-api/get/${video.video}?video=true&cachekey=${media_updated_at?.toString()}`}
|
||||
videoSrc={getStorageUrl({
|
||||
storageId: video.video,
|
||||
params: {
|
||||
cacheKey: media_updated_at?.toISOString(),
|
||||
media: "video",
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</CarouselItem>
|
||||
);
|
||||
|
|
@ -275,11 +300,23 @@ export const CardAnnuncio = ({
|
|||
{images && images.length > 0 && images[0] ? (
|
||||
<ImageFlbk
|
||||
alt={t.card.alt_immagine}
|
||||
blurDataURL={`/storage-api/get/${images[0].thumb}?image=true&cachekey=${media_updated_at?.toString()}`}
|
||||
blurDataURL={getStorageUrl({
|
||||
storageId: images[0].thumb,
|
||||
params: {
|
||||
cacheKey: media_updated_at?.toISOString(),
|
||||
media: "image",
|
||||
},
|
||||
})}
|
||||
className={"h-64 w-full bg-[#e6e9ec] object-cover"}
|
||||
height={1080}
|
||||
priority={true}
|
||||
src={`/storage-api/get/${images[0].img}?image=true&cachekey=${media_updated_at?.toString()}`}
|
||||
src={getStorageUrl({
|
||||
storageId: images[0].img,
|
||||
params: {
|
||||
cacheKey: media_updated_at?.toISOString(),
|
||||
media: "image",
|
||||
},
|
||||
})}
|
||||
width={1920}
|
||||
/>
|
||||
) : (
|
||||
|
|
@ -420,7 +457,13 @@ export const CarouselAnnuncio = ({
|
|||
height={400}
|
||||
onClick={() => handleOpenModal(idx)}
|
||||
priority={idx === 0}
|
||||
src={`/storage-api/get/${img.img}?image=true&cachekey=${updated_at?.toString()}`}
|
||||
src={getStorageUrl({
|
||||
storageId: img.img,
|
||||
params: {
|
||||
cacheKey: updated_at?.toISOString(),
|
||||
media: "image",
|
||||
},
|
||||
})}
|
||||
width={800}
|
||||
/>
|
||||
<Maximize2
|
||||
|
|
@ -442,9 +485,21 @@ export const CarouselAnnuncio = ({
|
|||
>
|
||||
<VideoPlayer
|
||||
className="aspect-square max-h-92 object-cover sm:max-h-80 xl:max-h-[25rem]"
|
||||
coverImage={`/storage-api/get/${video.thumb}?image=true&cachekey=${updated_at?.toString()}`}
|
||||
coverImage={getStorageUrl({
|
||||
storageId: video.thumb,
|
||||
params: {
|
||||
cacheKey: updated_at?.toISOString(),
|
||||
media: "image",
|
||||
},
|
||||
})}
|
||||
key={`videoplayer-${idx}-${openModal}`}
|
||||
videoSrc={`/storage-api/get/${video.video}?video=true&cachekey=${updated_at?.toString()}`}
|
||||
videoSrc={getStorageUrl({
|
||||
storageId: video.video,
|
||||
params: {
|
||||
cacheKey: updated_at?.toISOString(),
|
||||
media: "video",
|
||||
},
|
||||
})}
|
||||
/>
|
||||
|
||||
<Maximize2
|
||||
|
|
@ -485,7 +540,13 @@ export const CarouselAnnuncio = ({
|
|||
alt={`carousel-img-${idx}`}
|
||||
className="mx-auto h-[90vh] w-full rounded-md bg-[#e6e9ec] object-contain sm:w-[80vw]"
|
||||
height={1080}
|
||||
src={`/storage-api/get/${img.img}?image=true&cachekey=${updated_at?.toString()}`}
|
||||
src={getStorageUrl({
|
||||
storageId: img.img,
|
||||
params: {
|
||||
cacheKey: updated_at?.toISOString(),
|
||||
media: "image",
|
||||
},
|
||||
})}
|
||||
width={1920}
|
||||
/>
|
||||
</CarouselItem>
|
||||
|
|
@ -498,8 +559,20 @@ export const CarouselAnnuncio = ({
|
|||
>
|
||||
<VideoPlayer
|
||||
className="absolute mx-auto h-[90vh] w-full max-w-fit rounded-md object-contain"
|
||||
coverImage={`/storage-api/get/${video.thumb}?image=true&cachekey=${updated_at?.toString()}`}
|
||||
videoSrc={`/storage-api/get/${video.video}?video=true&cachekey=${updated_at?.toString()}`}
|
||||
coverImage={getStorageUrl({
|
||||
storageId: video.thumb,
|
||||
params: {
|
||||
cacheKey: updated_at?.toISOString(),
|
||||
media: "image",
|
||||
},
|
||||
})}
|
||||
videoSrc={getStorageUrl({
|
||||
storageId: video.video,
|
||||
params: {
|
||||
cacheKey: updated_at?.toISOString(),
|
||||
media: "video",
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</CarouselItem>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import {
|
|||
} from "~/components/ui/dropdown-menu";
|
||||
import { Separator } from "~/components/ui/separator";
|
||||
import { UploadModal } from "~/components/upload_modal";
|
||||
import { getStorageUrl } from "~/lib/storage_utils";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
|
|
@ -324,7 +325,12 @@ function FileList({
|
|||
{format(new Date(file.uploadedAt), "d MMM yyyy")}
|
||||
</div>
|
||||
<div className="col-span-2 flex justify-end gap-1 md:col-span-1">
|
||||
<Link href={`/storage-api/get/${file.id}?mode=download`}>
|
||||
<Link
|
||||
href={getStorageUrl({
|
||||
storageId: file.id,
|
||||
params: { mode: "download" },
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
className="flex size-8 gap-1 text-sm"
|
||||
size="icon"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { CircleCheck, ExternalLink, Trash2 } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import toast from "react-hot-toast";
|
||||
import { getStorageUrl } from "~/lib/storage_utils";
|
||||
import { useSession } from "~/providers/SessionProvider";
|
||||
import type { UsersId } from "~/schemas/public/Users";
|
||||
import type { UsersStorageUserStorageId } from "~/schemas/public/UsersStorage";
|
||||
|
|
@ -149,7 +150,9 @@ export const DocumentiUploadSection = ({
|
|||
alt={title}
|
||||
className="size-24 rounded-md border object-cover"
|
||||
height={96}
|
||||
src={`/storage-api/get/${document.storageId}`}
|
||||
src={getStorageUrl({
|
||||
storageId: document.storageId,
|
||||
})}
|
||||
width={96}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { Interactions } from "~/components/servizio/interactions";
|
|||
import { Button } from "~/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
|
||||
import { handleConsegna } from "~/lib/annuncio_details";
|
||||
import { getStorageUrl } from "~/lib/storage_utils";
|
||||
import { cn, formatCurrency } from "~/lib/utils";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
import { useServizioAnnuncio } from "~/providers/ServizioProvider";
|
||||
|
|
@ -58,7 +59,13 @@ export const BasicAnnuncioCard = ({
|
|||
priority
|
||||
src={
|
||||
(data?.images[0] &&
|
||||
`/storage-api/get/${data.images[0].img}?image=true&cachekey=${data.media_updated_at?.toString()}`) ||
|
||||
getStorageUrl({
|
||||
storageId: data.images[0].img,
|
||||
params: {
|
||||
cacheKey: data.media_updated_at?.toISOString(),
|
||||
media: "image",
|
||||
},
|
||||
})) ||
|
||||
"/fallback-image.png"
|
||||
}
|
||||
width={1920}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { useState } from "react";
|
|||
import toast from "react-hot-toast";
|
||||
import { AllegatoIframe } from "~/components/allegato-iframe";
|
||||
import { LoadingPage } from "~/components/loading";
|
||||
import { getStorageUrl } from "~/lib/storage_utils";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
import { useServizio, useServizioAnnuncio } from "~/providers/ServizioProvider";
|
||||
import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum";
|
||||
|
|
@ -40,7 +41,10 @@ export const FileSection = ({ storageId }: { storageId: string }) => {
|
|||
|
||||
<Link
|
||||
className="underline underline-offset-1 after:content-['_↗']"
|
||||
href={`/storage-api/get/${fileInfos.id}?mode=download`}
|
||||
href={getStorageUrl({
|
||||
storageId: fileInfos.id,
|
||||
params: { mode: "download" },
|
||||
})}
|
||||
>
|
||||
{t.file_section.download}
|
||||
</Link>
|
||||
|
|
|
|||
26
apps/infoalloggi/src/lib/storage_utils.ts
Normal file
26
apps/infoalloggi/src/lib/storage_utils.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { env } from "~/env";
|
||||
|
||||
type Params = {
|
||||
cacheKey: string;
|
||||
mode: "download" | "inline";
|
||||
media: "image" | "video";
|
||||
};
|
||||
|
||||
export function getStorageUrl({
|
||||
storageId,
|
||||
params,
|
||||
host = env.NEXT_PUBLIC_BASE_URL,
|
||||
}: {
|
||||
storageId: string;
|
||||
params?: Partial<Params>;
|
||||
host?: string;
|
||||
}) {
|
||||
const url = new URL(`${host}/storage-api/get/${storageId}`);
|
||||
if (params) {
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
url.searchParams.append(key, value);
|
||||
});
|
||||
}
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
|
|
@ -12,8 +12,8 @@ export const apisMiddleware = async (req: NextRequest) => {
|
|||
}
|
||||
|
||||
const params = new URLSearchParams(searchParams);
|
||||
const isImageRequest = params.get("image") === "true";
|
||||
const isVideoRequest = params.get("video") === "true";
|
||||
const isImageRequest = params.get("media") === "image";
|
||||
const isVideoRequest = params.get("media") === "video";
|
||||
|
||||
// Check if this is a Next.js Image Optimization request
|
||||
const purpose = req.headers.get("purpose");
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ import {
|
|||
import { useMediaQuery } from "~/hooks/use-media-query";
|
||||
import { handleConsegna } from "~/lib/annuncio_details";
|
||||
import { replaceWithBr } from "~/lib/newlineToBr";
|
||||
import { getStorageUrl } from "~/lib/storage_utils";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { AnnuncioContext } from "~/providers/AnnuncioProvider";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
|
|
@ -632,9 +633,15 @@ const AnnuncioFooter = ({
|
|||
return (
|
||||
<VideoPlayer
|
||||
className="h-96 max-w-96"
|
||||
coverImage={`/storage-api/get/${video.thumb}?image=true&cachekey=${updated_at?.toString()}`}
|
||||
coverImage={getStorageUrl({
|
||||
storageId: video.thumb,
|
||||
params: { cacheKey: updated_at?.toISOString(), media: "image" },
|
||||
})}
|
||||
key={`videoplayer-${video.video}`} // Cache busting
|
||||
videoSrc={`/storage-api/get/${video.video}?video=true&cachekey=${updated_at?.toString()}`}
|
||||
videoSrc={getStorageUrl({
|
||||
storageId: video.video,
|
||||
params: { cacheKey: updated_at?.toISOString(), media: "video" },
|
||||
})}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import {
|
|||
DialogTrigger,
|
||||
} from "~/components/ui/dialog";
|
||||
import { Input } from "~/components/ui/input";
|
||||
import { getStorageUrl } from "~/lib/storage_utils";
|
||||
import type { NextPageWithLayout } from "~/pages/_app";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
import { useEnforcedSession } from "~/providers/SessionProvider";
|
||||
|
|
@ -77,7 +78,12 @@ const AllegatoView: NextPageWithLayout<AllegatoViewProps> = ({
|
|||
<span>
|
||||
caricato il {new Date(fileInfos.uploadedAt).toLocaleString("it")}
|
||||
</span>
|
||||
<Link href={`/storage-api/get/${fileInfos.id}?mode=download`}>
|
||||
<Link
|
||||
href={getStorageUrl({
|
||||
storageId: fileInfos.id,
|
||||
params: { mode: "download" },
|
||||
})}
|
||||
>
|
||||
<Button className="flex gap-2">
|
||||
<Download size={16} />
|
||||
Download
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { DocNotFoundPage } from "~/components/doc_not_found";
|
|||
import { AreaRiservataLayout } from "~/components/Layout";
|
||||
import { LoadingPage } from "~/components/loading";
|
||||
import { Status500 } from "~/components/status-page";
|
||||
import { getStorageUrl } from "~/lib/storage_utils";
|
||||
import type { NextPageWithLayout } from "~/pages/_app";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
import type { AnnunciId } from "~/schemas/public/Annunci";
|
||||
|
|
@ -60,7 +61,10 @@ const FileSection = ({ storageId }: { storageId: string }) => {
|
|||
|
||||
<Link
|
||||
className="underline underline-offset-1 after:content-['_↗']"
|
||||
href={`/storage-api/get/${fileInfos.id}?mode=download`}
|
||||
href={getStorageUrl({
|
||||
storageId: fileInfos.id,
|
||||
params: { mode: "download" },
|
||||
})}
|
||||
>
|
||||
{t.file_section.download}
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { DocNotFoundPage } from "~/components/doc_not_found";
|
|||
import { AreaRiservataLayout } from "~/components/Layout";
|
||||
import { LoadingPage } from "~/components/loading";
|
||||
import { Status500 } from "~/components/status-page";
|
||||
import { getStorageUrl } from "~/lib/storage_utils";
|
||||
import type { NextPageWithLayout } from "~/pages/_app";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
import type { AnnunciId } from "~/schemas/public/Annunci";
|
||||
|
|
@ -56,7 +57,10 @@ const FileSection = ({ storageId }: { storageId: string }) => {
|
|||
|
||||
<Link
|
||||
className="underline underline-offset-1 after:content-['_↗']"
|
||||
href={`/storage-api/get/${fileInfos.id}?mode=download`}
|
||||
href={getStorageUrl({
|
||||
storageId: fileInfos.id,
|
||||
params: { mode: "download" },
|
||||
})}
|
||||
>
|
||||
{t.file_section.download}
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { TRPCError } from "@trpc/server";
|
||||
import { env } from "~/env";
|
||||
import { getStorageUrl } from "~/lib/storage_utils";
|
||||
import type {
|
||||
Annunci,
|
||||
AnnunciId,
|
||||
|
|
@ -115,7 +116,14 @@ export const getAnnunciMetaByCod = async ({ cod }: { cod: string }) => {
|
|||
}
|
||||
const ogImage =
|
||||
annuncio.images && annuncio.images.length > 0 && annuncio.images[0]
|
||||
? `${env.BASE_URL}/storage-api/get/${annuncio.images[0].img}?image=true&cachekey=${annuncio.media_updated_at?.toString()}`
|
||||
? getStorageUrl({
|
||||
storageId: annuncio.images[0].img,
|
||||
params: {
|
||||
cacheKey: annuncio.media_updated_at?.toISOString(),
|
||||
media: "image",
|
||||
},
|
||||
host: env.BASE_URL,
|
||||
})
|
||||
: `${env.BASE_URL}/og.jpg`;
|
||||
|
||||
return {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue