From 198e41e601c4fd064e3a093549441e99e2d28570 Mon Sep 17 00:00:00 2001 From: seaznCode Date: Thu, 20 Nov 2025 17:48:51 +0100 Subject: [PATCH] feat: edit subscription --- .../admin/subscriptions/edit/[id]/page.tsx | 226 ++++++++++++++++++ src/app/admin/subscriptions/page.tsx | 6 + 2 files changed, 232 insertions(+) create mode 100644 src/app/admin/subscriptions/edit/[id]/page.tsx diff --git a/src/app/admin/subscriptions/edit/[id]/page.tsx b/src/app/admin/subscriptions/edit/[id]/page.tsx new file mode 100644 index 0000000..917c983 --- /dev/null +++ b/src/app/admin/subscriptions/edit/[id]/page.tsx @@ -0,0 +1,226 @@ +"use client"; +import React, { useEffect, useState, useRef } from 'react'; +import { useRouter, useParams } from 'next/navigation'; +import Link from 'next/link'; +import PageLayout from '../../../../components/PageLayout'; +import useCoffeeManagement, { CoffeeItem } from '../../hooks/useCoffeeManagement'; +import { PhotoIcon } from '@heroicons/react/24/solid'; + +export default function EditSubscriptionPage() { + const router = useRouter(); + // next/navigation app router dynamic param + const params = useParams(); + const idParam = params?.id; + const id = typeof idParam === 'string' ? parseInt(idParam, 10) : Array.isArray(idParam) ? parseInt(idParam[0], 10) : NaN; + + const { listProducts, updateProduct } = useCoffeeManagement(); + + const [item, setItem] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + // Form state + const [title, setTitle] = useState(''); + const [description, setDescription] = useState(''); + const [price, setPrice] = useState(''); + const [currency, setCurrency] = useState('EUR'); + const [isFeatured, setIsFeatured] = useState(false); + const [state, setState] = useState(true); + const [pictureFile, setPictureFile] = useState(undefined); + const fileInputRef = useRef(null); + + useEffect(() => { + let active = true; + async function load() { + if (!id || Number.isNaN(id)) { + setError('Invalid subscription id'); + setLoading(false); + return; + } + try { + const all = await listProducts(); + const found = all.find((p: CoffeeItem) => p.id === id) || null; + if (!active) return; + if (!found) { + setError('Subscription not found'); + } else { + setItem(found); + setTitle(found.title || ''); + setDescription(found.description || ''); + setPrice(found.price != null ? String(found.price) : ''); + setCurrency(found.currency || 'EUR'); + setIsFeatured(!!found.is_featured); + setState(!!found.state); + } + } catch (e: any) { + if (active) setError(e?.message ?? 'Failed to load subscription'); + } finally { + if (active) setLoading(false); + } + } + load(); + return () => { active = false; }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [id]); + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + if (!item) return; + setError(null); + try { + const numericPrice = Number(price); + if (!Number.isFinite(numericPrice) || numericPrice < 0) { + setError('Price must be a valid non-negative number'); + return; + } + await updateProduct(item.id, { + title: title.trim(), + description: description.trim(), + price: numericPrice, + currency: currency.trim(), + is_featured: isFeatured, + state, + pictureFile, + }); + router.push('/admin/subscriptions'); + } catch (e: any) { + setError(e?.message ?? 'Update failed'); + } + } + + return ( + +
+
+
+
+
+

Edit Subscription

+

Update details of the subscription product.

+
+ + + Back to list + +
+
+ + {loading && ( +
Loading subscription…
+ )} + {error && !loading && ( +
{error}
+ )} + + {!loading && item && ( +
+
+
+
+ + setTitle(e.target.value)} + /> +
+
+ + setPrice(e.target.value)} + /> +
+
+ + setCurrency(e.target.value.toUpperCase().slice(0,3))} + /> +
+
+
+ setIsFeatured(e.target.checked)} /> + +
+
+ setState(e.target.checked)} /> + +
+
+
+ +
+ +