dev #21
@ -217,9 +217,9 @@ export default function CreateSubscriptionPage() {
|
|||||||
|
|
||||||
{/* Gallery Images */}
|
{/* Gallery Images */}
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-semibold text-slate-700 mb-1">Gallery Images</label>
|
<label className="block text-sm font-semibold text-slate-700 mb-1">{t('autofix.ka219f1d9')}</label>
|
||||||
<p className="text-xs text-slate-500 mb-3">
|
<p className="text-xs text-slate-500 mb-3">
|
||||||
Upload additional product images (JPG, PNG, WebP · max 10 MB each). These are sent as <code className="rounded bg-slate-100 px-1 py-0.5 text-slate-600">pictures</code> and returned in <code className="rounded bg-slate-100 px-1 py-0.5 text-slate-600">pictureUrls</code>.
|
Upload additional product images (JPG, PNG, WebP · max 10 MB each). These are sent as <code className="rounded bg-slate-100 px-1 py-0.5 text-slate-600">pictures</code>{t('autofix.k2992fa62')}<code className="rounded bg-slate-100 px-1 py-0.5 text-slate-600">pictureUrls</code>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Gallery grid */}
|
{/* Gallery grid */}
|
||||||
@ -232,9 +232,7 @@ export default function CreateSubscriptionPage() {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleSetThumbnailFromGallery(i)}
|
onClick={() => handleSetThumbnailFromGallery(i)}
|
||||||
className="absolute top-1 right-1 rounded-md bg-white/95 px-2 py-1 text-[10px] font-semibold text-slate-700 shadow hover:bg-white transition"
|
className="absolute top-1 right-1 rounded-md bg-white/95 px-2 py-1 text-[10px] font-semibold text-slate-700 shadow hover:bg-white transition"
|
||||||
>
|
>{t('autofix.k6c1bb40b')}</button>
|
||||||
Set thumbnail
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleRemoveGalleryImage(i)}
|
onClick={() => handleRemoveGalleryImage(i)}
|
||||||
|
|||||||
@ -383,9 +383,8 @@ export default function EditSubscriptionPage() {
|
|||||||
<div className="rounded-[28px] border border-white/80 bg-white/90 p-8 shadow-[0_24px_70px_-40px_rgba(15,23,42,0.3)] backdrop-blur space-y-6">
|
<div className="rounded-[28px] border border-white/80 bg-white/90 p-8 shadow-[0_24px_70px_-40px_rgba(15,23,42,0.3)] backdrop-blur space-y-6">
|
||||||
<div className="flex items-center justify-between gap-4 flex-wrap">
|
<div className="flex items-center justify-between gap-4 flex-wrap">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg font-bold text-slate-900">Gallery Images</h2>
|
<h2 className="text-lg font-bold text-slate-900">{t('autofix.ka219f1d9')}</h2>
|
||||||
<p className="text-xs text-slate-500 mt-0.5">
|
<p className="text-xs text-slate-500 mt-0.5">{t('autofix.k68ef9d49')}<span className="font-semibold text-slate-700">{t('autofix.k0496e5cc')}</span>.
|
||||||
Manage additional product images. Mark existing images for removal or add new ones, then click <span className="font-semibold text-slate-700">Save Gallery</span>.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{galleryHasChanges && (
|
{galleryHasChanges && (
|
||||||
@ -399,10 +398,10 @@ export default function EditSubscriptionPage() {
|
|||||||
|
|
||||||
{/* Existing pictures */}
|
{/* Existing pictures */}
|
||||||
{galleryLoading ? (
|
{galleryLoading ? (
|
||||||
<p className="text-sm text-slate-500">Loading gallery…</p>
|
<p className="text-sm text-slate-500">{t('autofix.k8811e423')}</p>
|
||||||
) : existingPictures.length > 0 ? (
|
) : existingPictures.length > 0 ? (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-3">Existing images</p>
|
<p className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-3">{t('autofix.kddb4db62')}</p>
|
||||||
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 gap-3">
|
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 gap-3">
|
||||||
{existingPictures.map(pic => {
|
{existingPictures.map(pic => {
|
||||||
const markedForRemoval = pendingRemoveIds.includes(pic.id);
|
const markedForRemoval = pendingRemoveIds.includes(pic.id);
|
||||||
@ -434,13 +433,13 @@ export default function EditSubscriptionPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-sm text-slate-400">No gallery images yet.</p>
|
<p className="text-sm text-slate-400">{t('autofix.k09e4edde')}</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* New images to upload */}
|
{/* New images to upload */}
|
||||||
{newGalleryPreviews.length > 0 && (
|
{newGalleryPreviews.length > 0 && (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-3">New images to add</p>
|
<p className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-3">{t('autofix.kad44a0f7')}</p>
|
||||||
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 gap-3">
|
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 gap-3">
|
||||||
{newGalleryPreviews.map((url, i) => (
|
{newGalleryPreviews.map((url, i) => (
|
||||||
<div key={i} className="relative group rounded-xl overflow-hidden border border-emerald-300 bg-slate-50 aspect-video">
|
<div key={i} className="relative group rounded-xl overflow-hidden border border-emerald-300 bg-slate-50 aspect-video">
|
||||||
@ -472,8 +471,7 @@ export default function EditSubscriptionPage() {
|
|||||||
|
|
||||||
{pendingRemoveIds.length > 0 && (
|
{pendingRemoveIds.length > 0 && (
|
||||||
<p className="text-xs text-rose-600">
|
<p className="text-xs text-rose-600">
|
||||||
{pendingRemoveIds.length} image{pendingRemoveIds.length > 1 ? 's' : ''} marked for removal. Click <span className="font-semibold">Save Gallery</span> or submit the form above to apply.
|
{pendingRemoveIds.length} image{pendingRemoveIds.length > 1 ? 's' : ''} marked for removal. Click <span className="font-semibold">{t('autofix.k0496e5cc')}</span>{t('autofix.kaabd9a3d')}</p>
|
||||||
</p>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -26,11 +26,9 @@ export default function CoffeeAbonnementDetailPage() {
|
|||||||
<div className="max-w-[1820px] mx-auto px-4 sm:px-6 xl:px-10 py-8 space-y-5">
|
<div className="max-w-[1820px] mx-auto px-4 sm:px-6 xl:px-10 py-8 space-y-5">
|
||||||
<div className="rounded-[28px] border border-white/80 bg-white/90 px-8 py-6 shadow-[0_24px_70px_-40px_rgba(15,23,42,0.3)] backdrop-blur flex flex-wrap items-center justify-between gap-4">
|
<div className="rounded-[28px] border border-white/80 bg-white/90 px-8 py-6 shadow-[0_24px_70px_-40px_rgba(15,23,42,0.3)] backdrop-blur flex flex-wrap items-center justify-between gap-4">
|
||||||
<div>
|
<div>
|
||||||
<div className="inline-flex items-center rounded-full border border-slate-200 bg-white px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.28em] text-slate-500">
|
<div className="inline-flex items-center rounded-full border border-slate-200 bg-white px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.28em] text-slate-500">{t('autofix.kbdc4e405')}</div>
|
||||||
Coffee ABO
|
<h1 className="mt-3 text-2xl font-bold tracking-tight text-slate-900">{t('autofix.k50bb594b')}</h1>
|
||||||
</div>
|
<p className="mt-1 text-sm text-slate-500">{t('autofix.ka157a704')}</p>
|
||||||
<h1 className="mt-3 text-2xl font-bold tracking-tight text-slate-900">Coffee Details</h1>
|
|
||||||
<p className="mt-1 text-sm text-slate-500">Detailed view with gallery images and product information.</p>
|
|
||||||
</div>
|
</div>
|
||||||
<Link
|
<Link
|
||||||
href="/coffee-abonnements"
|
href="/coffee-abonnements"
|
||||||
@ -38,9 +36,7 @@ export default function CoffeeAbonnementDetailPage() {
|
|||||||
>
|
>
|
||||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||||
</svg>
|
</svg>{t('autofix.k96839795')}</Link>
|
||||||
Back to selection
|
|
||||||
</Link>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{loading && (
|
{loading && (
|
||||||
@ -57,8 +53,8 @@ export default function CoffeeAbonnementDetailPage() {
|
|||||||
|
|
||||||
{!loading && !error && !coffee && (
|
{!loading && !error && !coffee && (
|
||||||
<div className="rounded-[28px] border border-white/80 bg-white/90 p-8 shadow-[0_24px_70px_-40px_rgba(15,23,42,0.3)] backdrop-blur">
|
<div className="rounded-[28px] border border-white/80 bg-white/90 p-8 shadow-[0_24px_70px_-40px_rgba(15,23,42,0.3)] backdrop-blur">
|
||||||
<h2 className="text-lg font-semibold text-slate-900">Coffee not found</h2>
|
<h2 className="text-lg font-semibold text-slate-900">{t('autofix.kbcb6ceea')}</h2>
|
||||||
<p className="mt-2 text-sm text-slate-500">The coffee may be unavailable or inactive right now.</p>
|
<p className="mt-2 text-sm text-slate-500">{t('autofix.k8e0e178e')}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -75,15 +71,15 @@ export default function CoffeeAbonnementDetailPage() {
|
|||||||
|
|
||||||
<div className="mt-5 space-y-2">
|
<div className="mt-5 space-y-2">
|
||||||
<div className="flex items-center justify-between rounded-xl border border-slate-200 bg-slate-50 px-4 py-2">
|
<div className="flex items-center justify-between rounded-xl border border-slate-200 bg-slate-50 px-4 py-2">
|
||||||
<span className="text-sm text-slate-600">Price per 10</span>
|
<span className="text-sm text-slate-600">{t('autofix.kab208d8e')}</span>
|
||||||
<span className="text-sm font-semibold text-slate-900">EUR {coffee.pricePer10.toFixed(2)}</span>
|
<span className="text-sm font-semibold text-slate-900">EUR {coffee.pricePer10.toFixed(2)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between rounded-xl border border-slate-200 bg-slate-50 px-4 py-2">
|
<div className="flex items-center justify-between rounded-xl border border-slate-200 bg-slate-50 px-4 py-2">
|
||||||
<span className="text-sm text-slate-600">Price per capsule</span>
|
<span className="text-sm text-slate-600">{t('autofix.ke0eb10f2')}</span>
|
||||||
<span className="text-sm font-semibold text-slate-900">EUR {(coffee.pricePer10 / 10).toFixed(2)}</span>
|
<span className="text-sm font-semibold text-slate-900">EUR {(coffee.pricePer10 / 10).toFixed(2)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between rounded-xl border border-slate-200 bg-slate-50 px-4 py-2">
|
<div className="flex items-center justify-between rounded-xl border border-slate-200 bg-slate-50 px-4 py-2">
|
||||||
<span className="text-sm text-slate-600">Gallery images</span>
|
<span className="text-sm text-slate-600">{t('autofix.k5bd8edf9')}</span>
|
||||||
<span className="text-sm font-semibold text-slate-900">
|
<span className="text-sm font-semibold text-slate-900">
|
||||||
{picturesLoading ? 'Loading...' : gallery.length}
|
{picturesLoading ? 'Loading...' : gallery.length}
|
||||||
</span>
|
</span>
|
||||||
@ -92,55 +88,14 @@ export default function CoffeeAbonnementDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="rounded-[28px] border border-white/80 bg-white/90 p-6 shadow-[0_24px_70px_-40px_rgba(15,23,42,0.3)] backdrop-blur">
|
<div className="rounded-[28px] border border-white/80 bg-white/90 p-6 shadow-[0_24px_70px_-40px_rgba(15,23,42,0.3)] backdrop-blur">
|
||||||
<p className="text-sm text-slate-600">Ready to add this coffee to your plan? Go back to the selection page and choose quantity in 10-piece steps.</p>
|
<p className="text-sm text-slate-600">{t('autofix.k31c4f5d9')}</p>
|
||||||
<Link
|
<Link
|
||||||
href="/coffee-abonnements"
|
href="/coffee-abonnements"
|
||||||
className="mt-4 inline-flex items-center justify-center rounded-xl bg-slate-900 px-4 py-2 text-sm font-semibold text-white hover:bg-slate-800 transition"
|
className="mt-4 inline-flex items-center justify-center rounded-xl bg-slate-900 px-4 py-2 text-sm font-semibold text-white hover:bg-slate-800 transition"
|
||||||
>
|
>{t('autofix.k47e6f301')}</Link>
|
||||||
Back and select coffee
|
|
||||||
</Link>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="xl:col-span-5 rounded-[28px] border border-white/80 bg-white/90 p-6 shadow-[0_24px_70px_-40px_rgba(15,23,42,0.3)] backdrop-blur">
|
|
||||||
<div className="flex items-center justify-between gap-3">
|
|
||||||
<h3 className="text-lg font-semibold text-slate-900">All Images</h3>
|
|
||||||
<span className="rounded-full border border-slate-200 bg-slate-50 px-3 py-1 text-xs font-semibold text-slate-600">
|
|
||||||
{picturesLoading ? 'Loading...' : `${gallery.length} image${gallery.length === 1 ? '' : 's'}`}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{picturesLoading ? (
|
|
||||||
<div className="mt-4 grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3">
|
|
||||||
<div className="h-24 rounded-xl bg-slate-100 animate-pulse" />
|
|
||||||
<div className="h-24 rounded-xl bg-slate-100 animate-pulse" />
|
|
||||||
<div className="h-24 rounded-xl bg-slate-100 animate-pulse" />
|
|
||||||
<div className="h-24 rounded-xl bg-slate-100 animate-pulse" />
|
|
||||||
<div className="h-24 rounded-xl bg-slate-100 animate-pulse" />
|
|
||||||
<div className="h-24 rounded-xl bg-slate-100 animate-pulse" />
|
|
||||||
</div>
|
|
||||||
) : gallery.length === 0 ? (
|
|
||||||
<p className="mt-4 text-sm text-slate-500">No gallery images are available for this coffee yet.</p>
|
|
||||||
) : (
|
|
||||||
<div className="mt-4 grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3">
|
|
||||||
{gallery.map((img, index) => (
|
|
||||||
<a
|
|
||||||
key={`${img}-${index}`}
|
|
||||||
href={img}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className="relative block h-24 overflow-hidden rounded-xl border border-slate-200 bg-slate-50 hover:border-slate-300 transition"
|
|
||||||
aria-label={`Open image ${index + 1}`}
|
|
||||||
>
|
|
||||||
<img src={img} alt={`${coffee.name} gallery ${index + 1}`} className="h-full w-full object-cover" />
|
|
||||||
<span className="absolute left-1.5 bottom-1.5 rounded bg-black/65 px-1.5 py-0.5 text-[10px] font-semibold text-white">
|
|
||||||
#{index + 1}
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -2086,7 +2086,27 @@ export const de: Translations = {
|
|||||||
"k8735e9a4": "<div>Ihr HTML hier</div>",
|
"k8735e9a4": "<div>Ihr HTML hier</div>",
|
||||||
"k88f0d12a": "Neue Vorlage",
|
"k88f0d12a": "Neue Vorlage",
|
||||||
"k987f2b90": "Erstellen",
|
"k987f2b90": "Erstellen",
|
||||||
"k9f7c3d1e": "Speichern"
|
"k9f7c3d1e": "Speichern",
|
||||||
|
"k0496e5cc": "Speicher Gallerie",
|
||||||
|
"k09e4edde": "No gallery images yet.",
|
||||||
|
"k2992fa62": "and returned in",
|
||||||
|
"k31c4f5d9": "Ready to add this coffee to your plan? Go back to the selection page and choose quantity in 10-piece steps.",
|
||||||
|
"k47e6f301": "Back and select coffee",
|
||||||
|
"k50bb594b": "Coffee Details",
|
||||||
|
"k5bd8edf9": "Gallery images",
|
||||||
|
"k68ef9d49": "Manage additional product images. Mark existing images for removal or add new ones, then click",
|
||||||
|
"k6c1bb40b": "Set thumbnail",
|
||||||
|
"k8811e423": "Loading gallery…",
|
||||||
|
"k8e0e178e": "The coffee may be unavailable or inactive right now.",
|
||||||
|
"ka157a704": "Detailed view with gallery images and product information.",
|
||||||
|
"ka219f1d9": "Gallery Images",
|
||||||
|
"kaabd9a3d": "or submit the form above to apply.",
|
||||||
|
"kab208d8e": "Price per 10",
|
||||||
|
"kad44a0f7": "New images to add",
|
||||||
|
"kbcb6ceea": "Coffee not found",
|
||||||
|
"kbdc4e405": "Coffee ABO",
|
||||||
|
"kddb4db62": "Existing images",
|
||||||
|
"ke0eb10f2": "Price per capsule"
|
||||||
},
|
},
|
||||||
"toasts": {
|
"toasts": {
|
||||||
"loginSuccess": "Anmeldung erfolgreich",
|
"loginSuccess": "Anmeldung erfolgreich",
|
||||||
@ -2110,6 +2130,5 @@ export const de: Translations = {
|
|||||||
"deleteSuccess": "Erfolgreich gelöscht.",
|
"deleteSuccess": "Erfolgreich gelöscht.",
|
||||||
"deleteFailed": "Löschen fehlgeschlagen. Bitte versuchen Sie es erneut.",
|
"deleteFailed": "Löschen fehlgeschlagen. Bitte versuchen Sie es erneut.",
|
||||||
"genericError": "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut."
|
"genericError": "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut."
|
||||||
},
|
}
|
||||||
"mailTemplates": {}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2086,7 +2086,27 @@ export const en: Translations = {
|
|||||||
"k8735e9a4": "<div>Your HTML here</div>",
|
"k8735e9a4": "<div>Your HTML here</div>",
|
||||||
"k88f0d12a": "New Template",
|
"k88f0d12a": "New Template",
|
||||||
"k987f2b90": "Create",
|
"k987f2b90": "Create",
|
||||||
"k9f7c3d1e": "Save"
|
"k9f7c3d1e": "Save",
|
||||||
|
"k0496e5cc": "Save Gallery",
|
||||||
|
"k09e4edde": "No gallery images yet.",
|
||||||
|
"k2992fa62": "and returned in",
|
||||||
|
"k31c4f5d9": "Ready to add this coffee to your plan? Go back to the selection page and choose quantity in 10-piece steps.",
|
||||||
|
"k47e6f301": "Back and select coffee",
|
||||||
|
"k50bb594b": "Coffee Details",
|
||||||
|
"k5bd8edf9": "Gallery images",
|
||||||
|
"k68ef9d49": "Manage additional product images. Mark existing images for removal or add new ones, then click",
|
||||||
|
"k6c1bb40b": "Set thumbnail",
|
||||||
|
"k8811e423": "Loading gallery…",
|
||||||
|
"k8e0e178e": "The coffee may be unavailable or inactive right now.",
|
||||||
|
"ka157a704": "Detailed view with gallery images and product information.",
|
||||||
|
"ka219f1d9": "Gallery Images",
|
||||||
|
"kaabd9a3d": "or submit the form above to apply.",
|
||||||
|
"kab208d8e": "Price per 10",
|
||||||
|
"kad44a0f7": "New images to add",
|
||||||
|
"kbcb6ceea": "Coffee not found",
|
||||||
|
"kbdc4e405": "Coffee ABO",
|
||||||
|
"kddb4db62": "Existing images",
|
||||||
|
"ke0eb10f2": "Price per capsule"
|
||||||
},
|
},
|
||||||
"toasts": {
|
"toasts": {
|
||||||
"loginSuccess": "Login successful",
|
"loginSuccess": "Login successful",
|
||||||
@ -2110,7 +2130,5 @@ export const en: Translations = {
|
|||||||
"deleteSuccess": "Deleted successfully.",
|
"deleteSuccess": "Deleted successfully.",
|
||||||
"deleteFailed": "Could not delete. Please try again.",
|
"deleteFailed": "Could not delete. Please try again.",
|
||||||
"genericError": "Something went wrong. Please try again."
|
"genericError": "Something went wrong. Please try again."
|
||||||
},
|
}
|
||||||
"mailTemplates": {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user