From d7aa44979e1c738d7028c8264f436a934a7df276 Mon Sep 17 00:00:00 2001 From: vickytechkey Date: Sun, 8 Nov 2026 17:30:31 +0530 Subject: [PATCH] feat: implement sellers serializers and frontend details views --- backend/sellers/serializers.py | 37 +++++++++++++++ .../routes/(app)/sellers/[id]/+page.svelte | 26 +++++++++- .../[id]/products/[productId]/+page.svelte | 47 +++++++++++++++---- 3 files changed, 101 insertions(+), 9 deletions(-) diff --git a/backend/sellers/serializers.py b/backend/sellers/serializers.py index 6793c8cc..63cc23f0 100644 --- a/backend/sellers/serializers.py +++ b/backend/sellers/serializers.py @@ -1,6 +1,30 @@ +import os +import re from decimal import Decimal from django.db.models import Sum, Q from rest_framework import serializers + +CDN_DOMAIN = os.environ.get("AWS_CLOUDFRONT_DOMAIN", "https://dc23efa04hj6d.cloudfront.net").rstrip("/") +if not CDN_DOMAIN.startswith("http"): + CDN_DOMAIN = f"https://{CDN_DOMAIN}" + + +def get_cdn_url(image_url): + if not image_url: + return image_url + url_str = str(image_url).strip() + if not url_str or url_str.startswith("data:image"): + return url_str + if "dc23efa04hj6d.cloudfront.net" in url_str: + return url_str + if "betasupplierdocumentstorage" in url_str or "amazonaws.com" in url_str or url_str.startswith("supplierdocument/"): + path = url_str.split("?")[0] + path = re.sub(r"^https?://[^/]+/", "", path) + if path.startswith("betasupplierdocumentstorage/"): + path = path[len("betasupplierdocumentstorage/"):] + path = path.lstrip("/") + return f"{CDN_DOMAIN}/{path}" + return url_str from .models import ( SupplierProfile, Product, @@ -63,6 +87,19 @@ class ProductSerializer(serializers.ModelSerializer): model = Product fields = "__all__" + def to_representation(self, instance): + data = super().to_representation(instance) + img = data.get("image") + if img: + data["image"] = get_cdn_url(img) + add_imgs = data.get("additional_images") + if isinstance(add_imgs, list): + data["additional_images"] = [get_cdn_url(ai) for ai in add_imgs if ai] + video = data.get("video_url") + if video: + data["video_url"] = get_cdn_url(video) + return data + class BulkUploadLogSerializer(serializers.ModelSerializer): class Meta: diff --git a/frontend/src/routes/(app)/sellers/[id]/+page.svelte b/frontend/src/routes/(app)/sellers/[id]/+page.svelte index 09253b74..07ccc7bc 100644 --- a/frontend/src/routes/(app)/sellers/[id]/+page.svelte +++ b/frontend/src/routes/(app)/sellers/[id]/+page.svelte @@ -128,6 +128,30 @@ } } + const CDN_DOMAIN = 'https://dc23efa04hj6d.cloudfront.net'; + + /** @param {string|null|undefined} url */ + function formatMediaUrl(url) { + if (!url) return ''; + const str = String(url).trim(); + if (!str || str.startsWith('data:image')) return str; + if (str.includes('dc23efa04hj6d.cloudfront.net')) return str; + if ( + str.includes('betasupplierdocumentstorage') || + str.includes('amazonaws.com') || + str.startsWith('supplierdocument/') + ) { + let path = str.split('?')[0]; + path = path.replace(/^https?:\/\/[^/]+\//, ''); + if (path.startsWith('betasupplierdocumentstorage/')) { + path = path.slice('betasupplierdocumentstorage/'.length); + } + path = path.replace(/^\/+/, ''); + return `${CDN_DOMAIN}/${path}`; + } + return str; + } + // Filtered products derived state let filteredProducts = $derived(() => { if (productFilter === 'all') return products; @@ -618,7 +642,7 @@
{#if p.image} - + {:else} diff --git a/frontend/src/routes/(app)/sellers/[id]/products/[productId]/+page.svelte b/frontend/src/routes/(app)/sellers/[id]/products/[productId]/+page.svelte index b8f5b71e..f7673b5d 100644 --- a/frontend/src/routes/(app)/sellers/[id]/products/[productId]/+page.svelte +++ b/frontend/src/routes/(app)/sellers/[id]/products/[productId]/+page.svelte @@ -30,11 +30,36 @@ let seller = $derived(data.seller || {}); let product = $derived(data.product || {}); + const CDN_DOMAIN = 'https://dc23efa04hj6d.cloudfront.net'; + + /** @param {string|null|undefined} url */ + function formatMediaUrl(url) { + if (!url) return ''; + const str = String(url).trim(); + if (!str || str.startsWith('data:image')) return str; + if (str.includes('dc23efa04hj6d.cloudfront.net')) return str; + if ( + str.includes('betasupplierdocumentstorage') || + str.includes('amazonaws.com') || + str.startsWith('supplierdocument/') + ) { + let path = str.split('?')[0]; + path = path.replace(/^https?:\/\/[^/]+\//, ''); + if (path.startsWith('betasupplierdocumentstorage/')) { + path = path.slice('betasupplierdocumentstorage/'.length); + } + path = path.replace(/^\/+/, ''); + return `${CDN_DOMAIN}/${path}`; + } + return str; + } + // Selected active image preview (defaults to product.image) let selectedImage = $state(''); $effect(() => { - if (product.image && !selectedImage) { - selectedImage = product.image; + const main = formatMediaUrl(product.image); + if (main && !selectedImage) { + selectedImage = main; } }); @@ -62,10 +87,12 @@ // Parse additional images array safely let allImages = $derived(() => { const list = []; - if (product.image) list.push(product.image); + const mainImg = formatMediaUrl(product.image); + if (mainImg) list.push(mainImg); if (Array.isArray(product.additional_images)) { for (const img of product.additional_images) { - if (img && !list.includes(img)) list.push(img); + const formatted = formatMediaUrl(img); + if (formatted && !list.includes(formatted)) list.push(formatted); } } return list; @@ -183,7 +210,11 @@
{#if selectedImage || product.image} - {product.title} + {product.title} {:else}
@@ -202,7 +233,7 @@ class:active={selectedImage === img || (!selectedImage && idx === 0)} onclick={() => (selectedImage = img)} > - + {/each}
@@ -213,7 +244,7 @@
{#if product.video_url}