Skip to content

Commit 8ccb412

Browse files
Merge pull request #58 from strapi/bug-deleted-image
[ ISSUE # 57 ] Created Srapi Image component to encapsulate strapiImage logic and update the app from crashing when user deletes image in Strapi.
2 parents 754bade + 37bd214 commit 8ccb412

File tree

10 files changed

+81
-43
lines changed

10 files changed

+81
-43
lines changed

next/components/blog-layout.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { IconArrowLeft } from "@tabler/icons-react";
22
import { Container } from "./container";
3-
import Image from "next/image";
43
import { Link } from "next-view-transitions";
54
import { format } from "date-fns";
6-
import { strapiImage } from "@/lib/strapi/strapiImage";
5+
import { StrapiImage } from "@/components/ui/strapi-image";
76
import DynamicZoneManager from "./dynamic-zone/manager";
87
import { Article } from "@/types/types";
98

@@ -26,11 +25,11 @@ export async function BlogLayout({
2625
</Link>
2726
</div>
2827
<div className="w-full mx-auto">
29-
{article.image ? (
30-
<Image
31-
src={strapiImage(article.image.url)}
32-
height="800"
33-
width="800"
28+
{article?.image ? (
29+
<StrapiImage
30+
src={article.image.url}
31+
height={800}
32+
width={800}
3433
className="h-40 md:h-96 w-full aspect-square object-cover rounded-3xl [mask-image:radial-gradient(circle,white,transparent)]"
3534
alt={article.title}
3635
/>
@@ -63,7 +62,7 @@ export async function BlogLayout({
6362
</div>
6463
<div className="flex space-x-2 items-center pt-12 border-t border-neutral-800 mt-12">
6564
<div className="flex space-x-2 items-center ">
66-
{/* <Image
65+
{/* <StrapiImage
6766
src={article.authorAvatar}
6867
alt={article.author}
6968
width={20}

next/components/dynamic-zone/brands.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
"use client";
22
import { useEffect, useState } from "react";
3-
import Image from "next/image";
43
import { Heading } from "../elements/heading";
54
import { Subheading } from "../elements/subheading";
65
import { AnimatePresence, motion } from "framer-motion";
7-
import { strapiImage } from "@/lib/strapi/strapiImage";
6+
import { StrapiImage } from "@/components/ui/strapi-image"
87

98
export const Brands = ({ heading, sub_heading, logos }: { heading: string, sub_heading: string, logos: any[] }) => {
109

@@ -71,11 +70,11 @@ export const Brands = ({ heading, sub_heading, logos }: { heading: string, sub_h
7170
key={logo.title}
7271
className="relative"
7372
>
74-
<Image
75-
src={strapiImage(logo.image.url)}
73+
<StrapiImage
74+
src={logo.image?.url}
7675
alt={logo.image.alternativeText}
77-
width="400"
78-
height="400"
76+
width={400}
77+
height={400}
7978
className="md:h-20 md:w-60 h-10 w-40 object-contain filter"
8079
draggable={false}
8180
/>

next/components/dynamic-zone/testimonials/slider.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
"use client";
22

3-
import { useState, useRef, useEffect, memo } from "react";
4-
import Image from "next/image";
5-
import { Transition } from "@headlessui/react";
3+
import { useState, useRef, useEffect, memo } from "react";import { Transition } from "@headlessui/react";
64
import { SparklesCore } from "../../ui/sparkles";
75
import { cn } from "@/lib/utils";
8-
import { strapiImage } from "@/lib/strapi/strapiImage";
6+
import { StrapiImage } from "@/components/ui/strapi-image"
97

108
export const TestimonialsSlider = ({ testimonials }: { testimonials: any }) => {
119
const [active, setActive] = useState<number>(0);
@@ -80,9 +78,9 @@ export const TestimonialsSlider = ({ testimonials }: { testimonials: any }) => {
8078
beforeEnter={() => heightFix()}
8179
>
8280
<div className="absolute inset-0 h-full -z-10">
83-
<Image
81+
<StrapiImage
8482
className="relative top-11 left-1/2 -translate-x-1/2 rounded-full"
85-
src={strapiImage(item.user.image.url)}
83+
src={item.user.image.url}
8684
width={56}
8785
height={56}
8886
alt={`${item.user.firstname} ${item.user.lastname}`}

next/components/dynamic-zone/testimonials/testimonials-marquee.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { cn } from "@/lib/utils";
33
import Image from "next/image";
44
import React from "react";
55
import Marquee from "react-fast-marquee";
6-
import { strapiImage } from "@/lib/strapi/strapiImage";
6+
import { StrapiImage } from "@/components/ui/strapi-image"
77

88
export const TestimonialsMarquee = ({ testimonials }: { testimonials: any }) => {
99
const levelOne = testimonials.slice(0, 8);
@@ -21,8 +21,8 @@ export const TestimonialsMarquee = ({ testimonials }: { testimonials: any }) =>
2121
>
2222
<Quote>{testimonial?.text}</Quote>
2323
<div className="flex gap-2 items-center mt-8">
24-
<Image
25-
src={strapiImage(testimonial?.user?.image?.url)}
24+
<StrapiImage
25+
src={testimonial?.user?.image?.url}
2626
alt={`${testimonial.user.firstname} ${testimonial.user.lastname}`}
2727
width={40}
2828
height={40}
@@ -52,8 +52,8 @@ export const TestimonialsMarquee = ({ testimonials }: { testimonials: any }) =>
5252
>
5353
<Quote>{testimonial.text}</Quote>
5454
<div className="flex gap-2 items-center mt-8">
55-
<Image
56-
src={strapiImage(testimonial?.user?.image?.url)}
55+
<StrapiImage
56+
src={testimonial?.user?.image?.url}
5757
alt={`${testimonial.user.firstname} ${testimonial.user.lastname}`}
5858
width={40}
5959
height={40}

next/components/products/featured.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import React from "react";
2-
import Image from "next/image";
32
import { formatNumber } from "@/lib/utils";
43
import { Link } from "next-view-transitions";
54
import { Product } from "@/types/types";
6-
import { strapiImage } from "@/lib/strapi/strapiImage";
5+
import { StrapiImage } from "@/components/ui/strapi-image"
76

87
export const Featured = ({ products, locale }: { products: Product[], locale: string }) => {
98
return (
@@ -41,8 +40,8 @@ const FeaturedItem = ({ product, locale }: { product: Product, locale:string })
4140
${formatNumber(product.price)}
4241
</span>
4342
</div>
44-
<Image
45-
src={strapiImage(product.images[0].url)}
43+
<StrapiImage
44+
src={product.images?.[0].url}
4645
alt={product.name}
4746
width={1000}
4847
height={1000}

next/components/products/modal.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Image from "next/image";
1111
import { useCart } from "@/context/cart-context";
1212
import { formatNumber } from "@/lib/utils";
1313
import { IconTrash } from "@tabler/icons-react";
14-
import { strapiImage } from "@/lib/strapi/strapiImage";
14+
import { StrapiImage } from "@/components/ui/strapi-image";
1515

1616
export default function AddToCartModal({ onClick }: { onClick: () => void }) {
1717
const { items, updateQuantity, getCartTotal, removeFromCart } = useCart();
@@ -38,8 +38,8 @@ export default function AddToCartModal({ onClick }: { onClick: () => void }) {
3838
className="flex gap-2 justify-between items-center py-4"
3939
>
4040
<div className="flex items-center gap-4">
41-
<Image
42-
src={strapiImage(item.product.images[0].url)}
41+
<StrapiImage
42+
src={item.product?.images?.[0].url}
4343
alt={item.product.name}
4444
width={60}
4545
height={60}

next/components/products/product-items.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import React from "react";
22
import { Product } from "@/types/types";
3-
import Image from "next/image";
43
import { formatNumber, truncate } from "@/lib/utils";
54
import { Link } from "next-view-transitions";
6-
import { strapiImage } from "@/lib/strapi/strapiImage";
5+
import { StrapiImage } from "@/components/ui/strapi-image";
76

87
export const ProductItems = ({
98
heading = "Popular",
@@ -43,8 +42,8 @@ const ProductItem = ({ product, locale }: { product: Product, locale: string })
4342
<div className="relative border border-neutral-800 rounded-md overflow-hidden">
4443
<div className="absolute inset-0 bg-gradient-to-b from-transparent via-transparent to-black transition-all duration-200 z-30" />
4544

46-
<Image
47-
src={strapiImage(product.images[0].url)}
45+
<StrapiImage
46+
src={product?.images?.[0].url}
4847
alt={product.name}
4948
width={600}
5049
height={600}

next/components/products/single-product.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import React, { useState } from "react";
33
import { Product } from "@/types/types";
44
import { motion } from "framer-motion";
5-
import Image from "next/image";
5+
import { StrapiImage } from "@/components/ui/strapi-image";
66
import { IconCheck } from "@tabler/icons-react";
77
import { cn, formatNumber } from "@/lib/utils";
88
import AddToCartModal from "@/components/products/modal";
@@ -30,7 +30,7 @@ export const SingleProduct = ({ product }: { product: Product }) => {
3030
damping: 35,
3131
}}
3232
>
33-
<Image
33+
<StrapiImage
3434
src={activeThumbnail}
3535
alt={product.name}
3636
width={600}

next/components/ui/animated-tooltip.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
"use client";
2-
import Image from "next/image";
32
import React, { useState } from "react";
43
import {
54
motion,
@@ -8,7 +7,7 @@ import {
87
useMotionValue,
98
useSpring,
109
} from "framer-motion";
11-
import { strapiImage } from "@/lib/strapi/strapiImage";
10+
import { StrapiImage } from "@/components/ui/strapi-image";
1211

1312
export const AnimatedTooltip = ({
1413
items,
@@ -79,12 +78,12 @@ export const AnimatedTooltip = ({
7978
</motion.div>
8079
)}
8180
</AnimatePresence>
82-
<Image
81+
<StrapiImage
8382
onMouseMove={handleMouseMove}
8483
height={100}
8584
width={100}
86-
src={strapiImage(item.image.url)}
87-
alt={item.image.alternativeText}
85+
src={item?.image?.url}
86+
alt={item?.image?.alternativeText}
8887
className="object-cover !m-0 !p-0 object-top rounded-full h-14 w-14 border-2 group-hover:scale-105 group-hover:z-30 border-white relative transition duration-500"
8988
/>
9089
</div>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import Image from "next/image";
2+
import { unstable_noStore as noStore } from 'next/cache';
3+
import { ComponentProps } from 'react';
4+
5+
interface StrapiImageProps extends Omit<ComponentProps<typeof Image>, 'src' | 'alt'> {
6+
src: string;
7+
alt: string | null;
8+
}
9+
10+
export function getStrapiMedia(url: string | null) {
11+
const strapiURL = process.env.NEXT_PUBLIC_API_URL;
12+
if (url == null) return null;
13+
if (url.startsWith("data:")) return url;
14+
if (url.startsWith("http") || url.startsWith("//")) return url;
15+
if (url.startsWith("/")) {
16+
if (!strapiURL && document?.location.host.endsWith(".strapidemo.com")) {
17+
return `https://${document.location.host.replace("client-", "api-")}${url}`
18+
}
19+
return strapiURL + url
20+
}
21+
return `${strapiURL}${url}`;
22+
}
23+
24+
export function StrapiImage({
25+
src,
26+
alt,
27+
className,
28+
...rest
29+
}: Readonly<StrapiImageProps>) {
30+
noStore();
31+
const imageUrl = getStrapiMedia(src);
32+
if (!imageUrl) return null;
33+
return (
34+
<Image
35+
src={imageUrl}
36+
alt={alt ?? "No alternative text provided"}
37+
className={className}
38+
{...rest}
39+
/>
40+
);
41+
}
42+
43+
44+
45+

0 commit comments

Comments
 (0)