Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 32 additions & 4 deletions src/components/inputs/image-upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Button } from "@/components/ui/button";
import { FormControl, FormLabel } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { ImageType } from "@/config/enums";
import type { ImageSize } from "@/features/abstract-resource-form";
import { ApiImage, uploadFile, useMutationWrapper } from "@/features/backend";
import { declineNoun } from "@/features/polish";
import type { Resource } from "@/features/resources";
Expand All @@ -20,15 +21,40 @@ import type {
ResourceSchemaKey,
} from "@/features/resources/types";
import { getToastMessages } from "@/lib/get-toast-messages";
import { cn } from "@/lib/utils";
import type { WrapperProps } from "@/types/components";

import { ImagePreviewModal } from "../presentation/image-preview-modal";

function InputBox({ children }: WrapperProps) {
function getImageSizeClasses(size: ImageSize): string {
switch (size) {
case "small": {
return "md:size-32";
}
case "medium": {
return "md:size-48";
}
case "large": {
return "md:size-64";
}
case "wide": {
return "md:h-48 md:w-full aspect-video";

Copilot AI Jan 14, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "wide" size applies md:h-48, md:w-full, and aspect-video simultaneously. This creates a conflict: md:w-full makes the element full width, aspect-video wants to maintain a 16:9 ratio, but md:h-48 fixes the height at 48px. These constraints cannot all be satisfied simultaneously. Consider either removing md:h-48 to let the aspect ratio control the height based on the full width, or replacing aspect-video with a max-height constraint if a fixed height is desired.

Suggested change
return "md:h-48 md:w-full aspect-video";
return "md:w-full aspect-video";

Copilot uses AI. Check for mistakes.
}

Copilot AI Feb 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getImageSizeClasses is declared to return string, but with no default/exhaustive guard the function can return undefined at runtime if an unexpected size value slips through (or if the ImageSize union is extended later). Consider adding an explicit fallback return, or an exhaustive never check to make this function total.

Suggested change
}
}
default: {
const _exhaustiveCheck: never = size;
throw new Error(`Unhandled image size: ${_exhaustiveCheck}`);
}

Copilot uses AI. Check for mistakes.
}
}

Comment on lines +29 to +45

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to nie powinna być funkcja ze switchem tylko obiekt jako mapa

function InputBox({
children,
size = "medium",
}: WrapperProps & { size?: ImageSize }) {
return (
<InputSlot
renderAs="div"
className="aspect-video h-fit max-h-48 w-full overflow-hidden rounded-lg md:size-48"
className={cn(
"h-fit w-full overflow-hidden rounded-lg",
size !== "wide" && "aspect-video max-h-48",

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a potential CSS conflict for small/medium/large sizes. The aspect-video class (line 55) applies at all breakpoints, while size-specific classes like md:size-32 (line 56) set explicit square dimensions at md+ breakpoint. This creates competing constraints where aspect-video requests a 16:9 ratio but md:size-32 sets equal width and height. Consider applying aspect-video only below the md breakpoint by using max-md:aspect-video, or clarify if the current behavior where explicit dimensions override aspect ratio is intentional.

Suggested change
size !== "wide" && "aspect-video max-h-48",
size !== "wide" && "max-md:aspect-video max-h-48",

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

użyj notacji { "aspect-vide max-h-48": size !== "wide" } zamiast && dla spójności z resztą kodu

getImageSizeClasses(size),
)}
>
{children}
</InputSlot>
Expand All @@ -41,6 +67,7 @@ export function ImageUpload<T extends Resource>({
value,
label,
type = ImageType.Logo,
size = "medium",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to zły pomysł żeby to były string literały. zmień to na enuma

existingImage,
resourceData,
disabled,
Expand All @@ -50,6 +77,7 @@ export function ImageUpload<T extends Resource>({
onChange: (value: string | null) => void;
label: string;
type?: ImageType;
size?: ImageSize;
existingImage?: ReactNode;
resourceData?: ResourceFormValues<T>;
disabled?: boolean;
Expand Down Expand Up @@ -112,7 +140,7 @@ export function ImageUpload<T extends Resource>({
<FormLabel className="flex flex-col items-start space-y-1.5">
{label}
{hasImage ? null : (
<InputBox>
<InputBox size={size}>
<div className="flex size-full cursor-pointer flex-col items-center justify-center">
<Camera className="text-image-input-icon size-12" />
<span className="text-muted-foreground text-xs">
Expand All @@ -123,7 +151,7 @@ export function ImageUpload<T extends Resource>({
)}
</FormLabel>
{hasImage ? (
<InputBox>
<InputBox size={size}>
<FormControl>
<Button
type="button"
Expand Down
2 changes: 2 additions & 0 deletions src/features/abstract-resource-form/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export * from "./components/abstract-resource-form";
export * from "./hooks/use-arf-sheet";

export * from "./providers/arf-sheet-provider";

export type { ImageSize } from "./types/inputs";

Copilot AI Feb 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ImageSize is being re-exported from the feature root, but most consumers import ARF types from @/features/abstract-resource-form/types (e.g. src/features/resources/types/internal.ts:6). To keep the public type surface consistent, consider also re-exporting ImageSize from src/features/abstract-resource-form/types/index.ts (or switching call sites to import from the same barrel).

Suggested change
export type { ImageSize } from "./types/inputs";

Copilot uses AI. Check for mistakes.
8 changes: 7 additions & 1 deletion src/features/abstract-resource-form/types/inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import type {
ResourceSchemaKey,
} from "@/features/resources/types";

export type ImageSize = "small" | "medium" | "large" | "wide";

export interface FormInputBase {
label: string;
/** For fields which should only be set on creation, and not in the edit form. */
Expand Down Expand Up @@ -51,7 +53,11 @@ type ArrayInputs<T extends Resource> = Partial<

export interface AbstractResourceFormInputs<T extends Resource> {
/** Image upload inputs for image key fields. */
imageInputs?: FormInput<T, z.ZodString, { type: ImageType }>;
imageInputs?: FormInput<
T,
z.ZodString,
{ type: ImageType; size?: ImageSize }
>;
/** Standard text input fields. */
textInputs?: FormInput<T>;
/** Number input fields for numeric values. */
Expand Down
12 changes: 8 additions & 4 deletions src/features/resources/data/resource-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,11 @@ export const RESOURCE_METADATA = {
description: { label: "Opis" },
},
imageInputs: {
coverPhotoKey: { label: "Zdjęcie w tle", type: ImageType.Banner },
coverPhotoKey: {
label: "Zdjęcie w tle",
type: ImageType.Banner,
size: "wide",
},
},
},
defaultValues: {
Expand Down Expand Up @@ -546,7 +550,7 @@ export const RESOURCE_METADATA = {
form: {
inputs: {
imageInputs: {
imageKey: { label: "Zdjęcie", type: ImageType.Banner },
imageKey: { label: "Zdjęcie", type: ImageType.Banner, size: "wide" },
},
textInputs: {
title: { label: "Tytuł" },
Expand Down Expand Up @@ -851,8 +855,8 @@ export const RESOURCE_METADATA = {
form: {
inputs: {
imageInputs: {
logoKey: { label: "Logo", type: ImageType.Logo },
coverKey: { label: "Baner", type: ImageType.Banner },
logoKey: { label: "Logo", type: ImageType.Logo, size: "small" },
coverKey: { label: "Baner", type: ImageType.Banner, size: "wide" },
},
textInputs: {
name: { label: "Nazwa" },
Expand Down