diff --git a/artifacts/teaboy-os/src/lib/image-url.ts b/artifacts/teaboy-os/src/lib/image-url.ts new file mode 100644 index 00000000..8b710760 --- /dev/null +++ b/artifacts/teaboy-os/src/lib/image-url.ts @@ -0,0 +1,7 @@ +export function resolveServiceImageUrl(value: string | null | undefined): string | null { + if (!value) return null; + const trimmed = value.trim(); + if (!trimmed) return null; + if (trimmed.startsWith("/objects/")) return `/api/storage${trimmed}`; + return trimmed; +} diff --git a/artifacts/teaboy-os/src/pages/admin.tsx b/artifacts/teaboy-os/src/pages/admin.tsx index 341ebc02..2439818e 100644 --- a/artifacts/teaboy-os/src/pages/admin.tsx +++ b/artifacts/teaboy-os/src/pages/admin.tsx @@ -24,6 +24,7 @@ import { import { useQueryClient } from "@tanstack/react-query"; import { useAuth } from "@/contexts/AuthContext"; import { useUpload, type UploadResponse } from "@workspace/object-storage-web"; +import { resolveServiceImageUrl } from "@/lib/image-url"; import { ArrowRight, ArrowLeft, Settings, Plus, Pencil, Trash2, Shield, Upload, Loader2, LayoutDashboard, Grid2X2, Coffee, Users as UsersIcon, Menu as MenuIcon } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -653,7 +654,7 @@ function ServiceImageUploader({ const { toast } = useToast(); const { uploadFile, isUploading, progress } = useUpload({ onSuccess: (resp: UploadResponse) => { - onChange(`/api/storage${resp.objectPath}`); + onChange(resp.objectPath); }, onError: (err: Error) => { toast({ title: t("admin.uploadFailed"), description: err.message, variant: "destructive" }); @@ -699,7 +700,7 @@ function ServiceImageUploader({ {value && (
{ (e.currentTarget as HTMLImageElement).style.display = "none"; }} diff --git a/artifacts/teaboy-os/src/pages/services.tsx b/artifacts/teaboy-os/src/pages/services.tsx index 4fb386de..99f45349 100644 --- a/artifacts/teaboy-os/src/pages/services.tsx +++ b/artifacts/teaboy-os/src/pages/services.tsx @@ -1,11 +1,32 @@ +import { useState } from "react"; import { useTranslation } from "react-i18next"; import { useLocation } from "wouter"; import { useListServices, getListServicesQueryKey, } from "@workspace/api-client-react"; -import { ArrowRight, ArrowLeft, Coffee } from "lucide-react"; +import { ArrowRight, ArrowLeft, Coffee, ImageIcon } from "lucide-react"; import { Badge } from "@/components/ui/badge"; +import { resolveServiceImageUrl } from "@/lib/image-url"; + +function ServiceCardImage({ src, alt }: { src: string | null; alt: string }) { + const [errored, setErrored] = useState(false); + const showImage = src && !errored; + return ( +
+ {showImage ? ( + {alt} setErrored(true)} + /> + ) : ( + + )} +
+ ); +} export default function ServicesPage() { const { t, i18n } = useTranslation(); @@ -49,22 +70,14 @@ export default function ServicesPage() { {services.map((service) => { const name = lang === "ar" ? service.nameAr : service.nameEn; const description = lang === "ar" ? service.descriptionAr : service.descriptionEn; + const resolvedImage = resolveServiceImageUrl(service.imageUrl); return (
- {service.imageUrl && ( -
- {name} { (e.currentTarget as HTMLImageElement).style.display = "none"; }} - /> -
- )} +

{name}