fix: normalize MicroDAO logo URLs using helper function
This commit is contained in:
@@ -4,6 +4,7 @@ import { useParams, useRouter } from "next/navigation";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useMicrodaoDetail, useMicrodaoRooms, useMicrodaoAgents } from "@/hooks/useMicrodao";
|
import { useMicrodaoDetail, useMicrodaoRooms, useMicrodaoAgents } from "@/hooks/useMicrodao";
|
||||||
import { DISTRICT_COLORS } from "@/lib/microdao";
|
import { DISTRICT_COLORS } from "@/lib/microdao";
|
||||||
|
import { normalizeAssetUrl } from "@/lib/utils/assetUrl";
|
||||||
import { MicrodaoVisibilityCard } from "@/components/microdao/MicrodaoVisibilityCard";
|
import { MicrodaoVisibilityCard } from "@/components/microdao/MicrodaoVisibilityCard";
|
||||||
import { MicrodaoBrandingCard } from "@/components/microdao/MicrodaoBrandingCard";
|
import { MicrodaoBrandingCard } from "@/components/microdao/MicrodaoBrandingCard";
|
||||||
import { MicrodaoRoomsSection } from "@/components/microdao/MicrodaoRoomsSection";
|
import { MicrodaoRoomsSection } from "@/components/microdao/MicrodaoRoomsSection";
|
||||||
@@ -145,9 +146,9 @@ export default function MicrodaoDetailPage() {
|
|||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
{microdao.logo_url && (
|
{normalizeAssetUrl(microdao.logo_url) && (
|
||||||
<img
|
<img
|
||||||
src={microdao.logo_url.startsWith('/') ? `/api/static${microdao.logo_url}` : microdao.logo_url.replace('/static/', '/api/static/')}
|
src={normalizeAssetUrl(microdao.logo_url)!}
|
||||||
alt={microdao.name}
|
alt={microdao.name}
|
||||||
className="w-16 h-16 md:w-20 md:h-20 rounded-2xl object-cover bg-slate-700/50 border border-white/10 shadow-lg"
|
className="w-16 h-16 md:w-20 md:h-20 rounded-2xl object-cover bg-slate-700/50 border border-white/10 shadow-lg"
|
||||||
/>
|
/>
|
||||||
@@ -188,10 +189,10 @@ export default function MicrodaoDetailPage() {
|
|||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<div className="hidden md:flex flex-col gap-3">
|
<div className="hidden md:flex flex-col gap-3">
|
||||||
<div className="w-24 h-24 rounded-2xl bg-slate-800 border border-white/10 flex items-center justify-center overflow-hidden shadow-xl">
|
<div className="w-24 h-24 rounded-2xl bg-slate-800 border border-white/10 flex items-center justify-center overflow-hidden shadow-xl">
|
||||||
{microdao.logo_url ? (
|
{normalizeAssetUrl(microdao.logo_url) ? (
|
||||||
// eslint-disable-next-line @next/next/no-img-element
|
// eslint-disable-next-line @next/next/no-img-element
|
||||||
<img
|
<img
|
||||||
src={microdao.logo_url.startsWith('/api/static') ? microdao.logo_url : microdao.logo_url.startsWith('/static') ? `/api${microdao.logo_url}` : microdao.logo_url}
|
src={normalizeAssetUrl(microdao.logo_url)!}
|
||||||
alt={microdao.name}
|
alt={microdao.name}
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useMicrodaoList } from "@/hooks/useMicrodao";
|
import { useMicrodaoList } from "@/hooks/useMicrodao";
|
||||||
import { DISTRICTS, DISTRICT_COLORS } from "@/lib/microdao";
|
import { DISTRICTS, DISTRICT_COLORS } from "@/lib/microdao";
|
||||||
|
import { normalizeAssetUrl } from "@/lib/utils/assetUrl";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { Building2, Users, MessageSquare, Search, MapPin, Crown, Globe, Lock, Layers } from "lucide-react";
|
import { Building2, Users, MessageSquare, Search, MapPin, Crown, Globe, Lock, Layers } from "lucide-react";
|
||||||
|
|
||||||
@@ -93,9 +94,9 @@ export default function MicrodaoListPage() {
|
|||||||
<div className="flex items-start justify-between gap-3">
|
<div className="flex items-start justify-between gap-3">
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<div className="shrink-0">
|
<div className="shrink-0">
|
||||||
{m.logo_url ? (
|
{normalizeAssetUrl(m.logo_url) ? (
|
||||||
<img
|
<img
|
||||||
src={m.logo_url.startsWith('/') ? `/api/static${m.logo_url}` : m.logo_url.replace('/static/', '/api/static/')}
|
src={normalizeAssetUrl(m.logo_url)!}
|
||||||
alt={m.name}
|
alt={m.name}
|
||||||
className="w-12 h-12 rounded-xl object-cover bg-slate-700/50"
|
className="w-12 h-12 rounded-xl object-cover bg-slate-700/50"
|
||||||
onError={(e) => {
|
onError={(e) => {
|
||||||
|
|||||||
35
apps/web/src/lib/utils/assetUrl.ts
Normal file
35
apps/web/src/lib/utils/assetUrl.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Normalize asset URL for display
|
||||||
|
* Handles various URL formats from the backend:
|
||||||
|
* - /api/static/uploads/... - already correct
|
||||||
|
* - /assets/... - static assets, use as-is
|
||||||
|
* - /static/uploads/... - needs /api prefix
|
||||||
|
* - https://... - external URL, use as-is
|
||||||
|
*/
|
||||||
|
export function normalizeAssetUrl(url: string | null | undefined): string | null {
|
||||||
|
if (!url) return null;
|
||||||
|
|
||||||
|
// Already correct format
|
||||||
|
if (url.startsWith('/api/static')) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static assets in public folder
|
||||||
|
if (url.startsWith('/assets/')) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// External URLs
|
||||||
|
if (url.startsWith('http://') || url.startsWith('https://')) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Old format - needs /api prefix
|
||||||
|
if (url.startsWith('/static/')) {
|
||||||
|
return `/api${url}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unknown format - return as-is
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user