feat(recipe-form): reject files > 5 MB and show Max. 5 MB hint
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -61,10 +61,19 @@
|
|||||||
);
|
);
|
||||||
let steps = $state(initial?.steps.map((s) => s.instruction) ?? ['']);
|
let steps = $state(initial?.steps.map((s) => s.instruction) ?? ['']);
|
||||||
let heroImageUrl = $state<string | null>(initial?.heroImageUrl ?? null);
|
let heroImageUrl = $state<string | null>(initial?.heroImageUrl ?? null);
|
||||||
|
let imageError = $state<string | null>(null);
|
||||||
|
|
||||||
|
const MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
||||||
|
|
||||||
function handleImageChange(e: Event) {
|
function handleImageChange(e: Event) {
|
||||||
const file = (e.currentTarget as HTMLInputElement).files?.[0];
|
const file = (e.currentTarget as HTMLInputElement).files?.[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
if (file.size > MAX_IMAGE_BYTES) {
|
||||||
|
imageError = 'Datei zu groß. Maximal 5 MB erlaubt.';
|
||||||
|
(e.currentTarget as HTMLInputElement).value = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
imageError = null;
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
heroImageUrl = reader.result as string;
|
heroImageUrl = reader.result as string;
|
||||||
@@ -196,6 +205,11 @@
|
|||||||
/>
|
/>
|
||||||
{heroImageUrl ? 'Bild ändern' : 'Bild hochladen'}
|
{heroImageUrl ? 'Bild ändern' : 'Bild hochladen'}
|
||||||
</label>
|
</label>
|
||||||
|
{#if imageError}
|
||||||
|
<p class="mt-[6px] text-[12px] text-[var(--color-error)]">{imageError}</p>
|
||||||
|
{:else}
|
||||||
|
<p class="mt-[6px] text-[11px] text-[var(--color-text-muted)]">Max. 5 MB</p>
|
||||||
|
{/if}
|
||||||
<input type="hidden" name="heroImageUrl" value={heroImageUrl ?? ''} />
|
<input type="hidden" name="heroImageUrl" value={heroImageUrl ?? ''} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -162,4 +162,31 @@ describe('RecipeForm', () => {
|
|||||||
render(RecipeForm, { props: emptyProps });
|
render(RecipeForm, { props: emptyProps });
|
||||||
expect(screen.queryByRole('alert')).not.toBeInTheDocument();
|
expect(screen.queryByRole('alert')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('shows Max. 5 MB hint below upload button', () => {
|
||||||
|
render(RecipeForm, { props: emptyProps });
|
||||||
|
expect(screen.getByText('Max. 5 MB')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows error when selected file exceeds 5 MB', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
render(RecipeForm, { props: emptyProps });
|
||||||
|
|
||||||
|
const oversizedFile = new File(['x'.repeat(6 * 1024 * 1024)], 'big.jpg', { type: 'image/jpeg' });
|
||||||
|
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
|
||||||
|
await user.upload(fileInput, oversizedFile);
|
||||||
|
|
||||||
|
expect(screen.getByText(/datei zu groß/i)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not show file size error for file within 5 MB', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
render(RecipeForm, { props: emptyProps });
|
||||||
|
|
||||||
|
const okFile = new File(['x'.repeat(1 * 1024 * 1024)], 'small.jpg', { type: 'image/jpeg' });
|
||||||
|
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
|
||||||
|
await user.upload(fileInput, okFile);
|
||||||
|
|
||||||
|
expect(screen.queryByText(/datei zu groß/i)).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user