Custom add and create flow polish

This commit is contained in:
adilallo
2026-05-08 20:32:24 -06:00
parent 26bcd61ea3
commit 026a1e6d71
68 changed files with 6208 additions and 527 deletions
@@ -14,8 +14,8 @@ import { memo, useCallback, useRef, useState } from "react";
import { useMessages, useTranslation } from "../../../contexts/MessagesContext";
import Chip from "../../../components/controls/Chip";
import IncrementerBlock from "../../../components/controls/IncrementerBlock";
import InlineTextButton from "../../../components/buttons/InlineTextButton";
import Upload from "../../../components/controls/Upload";
import { getAssetPath } from "../../../../lib/assetUtils";
import ApplicableScopeField from "./ApplicableScopeField";
import InputLabel from "../../../components/type/InputLabel";
import type { CustomMethodCardFieldBlock } from "../../../../lib/create/customMethodCardFieldBlocks";
@@ -44,7 +44,9 @@ function CustomMethodCardUploadBlockRow({
patch,
uploadFileInputAriaLabel,
uploadHint,
clearFileLabel,
clearPendingUploadAriaLabel,
clearPendingUploadTooltip,
uploadPreviewImageAlt,
noFileChosen,
}: {
block: Extract<CustomMethodCardFieldBlock, { kind: "upload" }>;
@@ -52,7 +54,9 @@ function CustomMethodCardUploadBlockRow({
patch: (_next: CustomMethodCardFieldBlock[]) => void;
uploadFileInputAriaLabel: string;
uploadHint: string;
clearFileLabel: string;
clearPendingUploadAriaLabel: string;
clearPendingUploadTooltip: string;
uploadPreviewImageAlt: string;
noFileChosen: string;
}) {
const uploadInputRef = useRef<HTMLInputElement | null>(null);
@@ -60,8 +64,17 @@ function CustomMethodCardUploadBlockRow({
const [busy, setBusy] = useState(false);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const displayName = block.fileName?.trim() ? block.fileName : noFileChosen;
const hasAsset = Boolean(block.assetUrl?.trim());
const previewAlt = block.fileName?.trim() || block.blockTitle || noFileChosen;
const assetUrlTrimmed = block.assetUrl?.trim() ?? "";
const hasAsset = assetUrlTrimmed.length > 0;
const clearUpload = () =>
patch(
mapBlockById(blocks, block.id, (b) =>
b.kind === "upload"
? { ...b, fileName: undefined, assetUrl: undefined }
: b,
),
);
return (
<div className="flex flex-col gap-2">
@@ -76,14 +89,6 @@ function CustomMethodCardUploadBlockRow({
{displayName}
</p>
) : null}
{hasAsset ? (
// eslint-disable-next-line @next/next/no-img-element -- same-origin upload URL
<img
src={block.assetUrl!.trim()}
alt={previewAlt}
className="max-h-[160px] max-w-full rounded-[var(--measures-radius-200,8px)] object-contain"
/>
) : null}
<input
ref={uploadInputRef}
type="file"
@@ -123,13 +128,41 @@ function CustomMethodCardUploadBlockRow({
})();
}}
/>
<Upload
active={!busy}
hintText={busy ? tUpload("uploading") : uploadHint}
onClick={() => {
if (!busy) uploadInputRef.current?.click();
}}
/>
{hasAsset ? (
<div className="relative inline-block max-w-full">
<button
type="button"
onClick={clearUpload}
className="absolute right-[8px] top-[8px] z-[1] flex h-[32px] w-[32px] cursor-pointer items-center justify-center rounded-full bg-[var(--color-surface-default-secondary)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-border-invert-primary)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-surface-default-primary)]"
aria-label={clearPendingUploadAriaLabel}
title={clearPendingUploadTooltip}
>
{/* eslint-disable-next-line @next/next/no-img-element -- matches ModalHeader close control */}
<img
src={getAssetPath("assets/Icon_Close.svg")}
alt=""
className="h-[16px] w-[16px]"
style={{
filter: "brightness(0) invert(1)",
}}
/>
</button>
{/* eslint-disable-next-line @next/next/no-img-element -- same-origin upload URL */}
<img
src={assetUrlTrimmed}
alt={uploadPreviewImageAlt}
className="max-h-[160px] max-w-full rounded-[var(--measures-radius-200,8px)] object-contain"
/>
</div>
) : (
<Upload
active={!busy}
hintText={busy ? tUpload("uploading") : uploadHint}
onClick={() => {
if (!busy) uploadInputRef.current?.click();
}}
/>
)}
{errorMessage ? (
<p
className="font-[family-name:var(--font-body)] text-[length:var(--font-size-body-s)] text-[var(--color-content-default-secondary)]"
@@ -138,21 +171,6 @@ function CustomMethodCardUploadBlockRow({
{errorMessage}
</p>
) : null}
{block.fileName?.trim() || block.assetUrl?.trim() ? (
<InlineTextButton
onClick={() =>
patch(
mapBlockById(blocks, block.id, (b) =>
b.kind === "upload"
? { ...b, fileName: undefined, assetUrl: undefined }
: b,
),
)
}
>
{clearFileLabel}
</InlineTextButton>
) : null}
</div>
);
}
@@ -297,7 +315,13 @@ function CustomMethodCardFieldBlocksSummaryComponent({
patch={patch}
uploadFileInputAriaLabel={fm.upload.uploadFileInputAriaLabel}
uploadHint={fm.upload.uploadHint}
clearFileLabel={em.clearFileLabel}
clearPendingUploadAriaLabel={
fm.upload.clearPendingUploadAriaLabel
}
clearPendingUploadTooltip={
fm.upload.clearPendingUploadTooltip
}
uploadPreviewImageAlt={fm.upload.uploadPreviewImageAlt}
noFileChosen={noFileChosen}
/>
)}