Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/bicyblex/bicyblexStore/llms.txt

Use this file to discover all available pages before exploring further.

All product images uploaded through the admin dashboard are automatically converted to WebP format before being stored in Supabase Storage. This client-side conversion reduces file sizes and ensures consistent image delivery across the storefront. News article cover images follow a similar upload flow but retain their original format.

convertToWebP(file, quality) utility

The convertToWebP function in src/utils/imageUtils.js handles the entire conversion process in the browser using the Canvas API. It accepts any image format the browser supports and returns a Promise<File> that resolves to a .webp file. Parameters:
ParameterTypeDefaultDescription
fileFileThe original image file selected by the user
qualitynumber0.8WebP compression quality (0–1, where 1 is lossless)
Returns: Promise<File> — a new File object with the .webp extension.
src/utils/imageUtils.js
export const convertToWebP = (file, quality = 0.8) => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = (event) => {
      const img = new Image();
      img.src = event.target.result;
      img.onload = () => {
        const canvas = document.createElement("canvas");
        canvas.width = img.width;
        canvas.height = img.height;
        const ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0);

        canvas.toBlob(
          (blob) => {
            if (blob) {
              // Creamos un nuevo objeto File con la extensión .webp
              const webpFile = new File(
                [blob],
                file.name.replace(/\.[^/.]+$/, ".webp"),
                {
                  type: "image/webp",
                }
              );
              resolve(webpFile);
            } else {
              reject(new Error("Error al convertir a WebP"));
            }
          },
          "image/webp",
          quality
        );
      };
    };
    reader.onerror = (error) => reject(error);
  });
};
The conversion process:
  1. FileReader reads the original file as a data URL
  2. An Image element loads the data URL to get the original dimensions
  3. A <canvas> is created at the same dimensions and the image is drawn onto it
  4. canvas.toBlob() exports the canvas as a WebP blob at the specified quality
  5. The blob is wrapped in a new File with the .webp extension
The default quality is 0.8 (80%), which gives a good balance between file size and visual quality. To adjust it, pass a custom value: convertToWebP(file, 0.9) for higher quality or convertToWebP(file, 0.6) for smaller files.

Product image upload flow

When an admin submits a new or updated product with an image, ProductManager.jsx runs the following sequence:
1

User selects an image file

The product form accepts any image type via <input type="file" accept="image/*">. The selected file is stored in formData.imageFile.
2

Convert to WebP

Before upload, the image is converted client-side:
const webpFile = await convertToWebP(payload.imageFile);
3

Upload to Supabase Storage

The converted file is uploaded to the products bucket with a unique timestamped filename:
const fileName = `${Date.now()}_${Math.random().toString(36).substring(7)}.webp`;
const { data, error } = await supabase.storage
  .from("products")
  .upload(fileName, webpFile);
4

Retrieve the public URL

After upload, the public URL is fetched and saved in the product row:
const { data: publicUrlData } = supabase.storage
  .from("products")
  .getPublicUrl(fileName);
imageUrl = publicUrlData.publicUrl;
5

Save the product record

The product is inserted or updated in the products table with the image field set to the public URL:
const finalPayload = {
  name: payload.name,
  price: parseFloat(payload.price) || 0,
  stock: parseInt(payload.stock) || 0,
  category_id: parseInt(payload.categoryId),
  specs: payload.specs || {},
  image: imageUrl,
  tag: payload.tag || "general",
};
await supabase.from("products").insert([finalPayload]);
// or .update(finalPayload).eq("id", payload.id) for edits

News image upload flow

News article cover images follow a similar upload pattern, but they are not converted to WebP — the original file extension is preserved. Images are stored under the news/ path prefix inside the news bucket.
const fileExt = imageFile.name.split(".").pop();
const fileName = `${Date.now()}-${Math.random().toString(36).substring(2)}.${fileExt}`;
const filePath = `news/${fileName}`;

const { error: uploadError } = await supabase.storage.from("news").upload(filePath, imageFile);

const { data: publicUrlData } = supabase.storage
  .from("news")
  .getPublicUrl(filePath);

imageUrl = publicUrlData.publicUrl;
When editing an existing article, the image is only replaced if a new file is selected. Otherwise, the existing image URL is preserved.

Storage buckets summary

BucketUsed forPath patternImage format
productsProduct images{timestamp}_{random}.webpWebP (converted client-side)
newsNews article cover imagesnews/{timestamp}-{random}.{ext}Original format
Both buckets must be set to public in the Supabase dashboard for the image URLs to be accessible on the storefront. See Supabase Setup for instructions on creating and configuring the buckets.
Deleted products and news articles do not automatically remove their images from Supabase Storage. Orphaned files accumulate over time. Implement a cleanup mechanism or periodically audit the buckets if storage usage is a concern.

Build docs developers (and LLMs) love