File size: 3,789 Bytes
bea55e2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { NextRequest, NextResponse } from 'next/server';

const SUPABASE_ANON_KEY = process.env.SUPABASE_ANON_KEY || '';
const SUPABASE_TOKEN = process.env.SUPABASE_TOKEN || '';
const EDGE_FUNCTIONS_URL = 'https://tcwdbokruvlizkxcpkzj.supabase.co/functions/v1';
const COOKIE_NAME = 'cellex_session_id';

/**
 * Upload Product Image API
 *
 * Receives a base64-encoded image (data URL) from the seller's device and stores
 * it in a dedicated product_images table. Returns an image URL that can be used
 * as the src of <img> tags.
 *
 * POST body:
 *   - productId?: number  (optional — when editing existing product)
 *   - imageData: base64 data URL (data:image/jpeg;base64,...  OR  data:image/png;base64,...)
 *
 * Response:
 *   - { success: true, imageUrl: "/api/image?id=<uuid>" }
 *   - { success: false, error: string }
 *
 * Notes:
 *   - Max 5MB per image (base64 will be ~6.7MB).
 *   - When productId is omitted (creating a NEW product), we still store the image
 *     and return a URL — the seller-products edge function will link the URL to
 *     the product via image_url column on create.
 */
export async function POST(request: NextRequest) {
  if (!SUPABASE_ANON_KEY) {
    return NextResponse.json({ success: false, error: 'SUPABASE_ANON_KEY not set' }, { status: 500 });
  }

  const sessionId = request.cookies.get(COOKIE_NAME)?.value || '';
  if (!sessionId) {
    return NextResponse.json({ success: false, error: 'Not authenticated' }, { status: 401 });
  }

  let body: any;
  try { body = await request.json(); } catch {
    return NextResponse.json({ success: false, error: 'Invalid JSON' }, { status: 400 });
  }

  const { productId, imageData } = body;
  if (!imageData || typeof imageData !== 'string') {
    return NextResponse.json({ success: false, error: 'imageData required' }, { status: 400 });
  }

  // Enforce 5MB ceiling on original file (base64 ~1.33x)
  if (imageData.length > 7 * 1024 * 1024) {
    return NextResponse.json({ success: false, error: 'Image too large. Max 5MB.' }, { status: 400 });
  }

  try {
    const authResp = await fetch(`${EDGE_FUNCTIONS_URL}/auth`, {
      method: 'POST',
      headers: { 'apikey': SUPABASE_ANON_KEY, 'Authorization': `Bearer ${sessionId}`, 'Content-Type': 'application/json' },
      body: JSON.stringify({ op: 'session' }),
    });
    const authData = await authResp.json();
    if (!authData.success || !authData.user) {
      return NextResponse.json({ success: false, error: 'Not authenticated' }, { status: 401 });
    }
    const userId = authData.user.id;

    const base64Data = imageData.includes(',') ? imageData.split(',')[1] : imageData;
    const contentType = imageData.match(/data:(image\/[^;]+)/)?.[1] || 'image/jpeg';

    const sqlHeaders: Record<string, string> = {
      'Authorization': `Bearer ${SUPABASE_TOKEN}`,
      'Content-Type': 'application/json',
    };

    const productIdSql = productId ? `${productId}` : 'NULL';
    const resp = await fetch('https://api.supabase.com/v1/projects/tcwdbokruvlizkxcpkzj/database/query', {
      method: 'POST',
      headers: sqlHeaders,
      body: JSON.stringify({
        query: `INSERT INTO product_images (product_id, seller_id, image_data, content_type) VALUES (${productIdSql}, '${userId}'::uuid, '${base64Data}', '${contentType}') RETURNING id;`,
      }),
    });

    const data = await resp.json();
    if (Array.isArray(data) && data.length > 0) {
      const imageId = data[0].id;
      const imageUrl = `/api/image?id=${imageId}`;
      return NextResponse.json({ success: true, imageUrl });
    }

    return NextResponse.json({ success: false, error: 'Failed to upload image' }, { status: 500 });
  } catch (error) {
    return NextResponse.json({ success: false, error: String(error) }, { status: 500 });
  }
}