mirror of
https://github.com/stack-auth/stack.git
synced 2026-07-20 21:29:36 +08:00
Apply review feedback to editable-grid and product page
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
fc2f817af9
commit
c3786b81be
@ -241,7 +241,9 @@ function ProductTitleEditor({
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" && !event.nativeEvent.isComposing) {
|
||||
event.preventDefault();
|
||||
runAsynchronouslyWithAlert(save());
|
||||
if (draftValue !== storedDisplayName && !isSaving) {
|
||||
runAsynchronouslyWithAlert(save());
|
||||
}
|
||||
}
|
||||
if (event.key === "Escape") {
|
||||
cancelEditing();
|
||||
@ -352,6 +354,12 @@ function ProductHeader({ productId, product, productLineName }: ProductHeaderPro
|
||||
icon: <FolderOpenIcon className="h-4 w-4" />,
|
||||
onClick: () => router.push(`/projects/${projectId}/payments/product-lines#product-${productId}`),
|
||||
},
|
||||
{
|
||||
id: "edit",
|
||||
label: "Edit full details",
|
||||
icon: <PencilSimpleIcon className="h-4 w-4" />,
|
||||
onClick: () => router.push(`/projects/${projectId}/payments/products/${productId}/edit`),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
@ -690,6 +698,14 @@ function ProductDetailsSection({ productId, product, config }: ProductDetailsSec
|
||||
setFreeTrialPopoverOpen(false);
|
||||
};
|
||||
|
||||
const handleFreeTrialPopoverOpenChange = (open: boolean) => {
|
||||
setFreeTrialPopoverOpen(open);
|
||||
if (open) {
|
||||
setFreeTrialCount(localFreeTrial ? localFreeTrial[0] : 7);
|
||||
setFreeTrialUnit(localFreeTrial ? localFreeTrial[1] : 'day');
|
||||
}
|
||||
};
|
||||
|
||||
// ===== PRICES HANDLERS (for deferred save) =====
|
||||
const handlePricesChange = (newPrices: Product['prices']) => {
|
||||
// Clear the "needs at least one price" error as soon as the user adds one back.
|
||||
@ -785,7 +801,7 @@ function ProductDetailsSection({ productId, product, config }: ProductDetailsSec
|
||||
name: "Free Trial",
|
||||
tooltip: "Free trial period before billing starts. Customers won't be charged during this period.",
|
||||
open: freeTrialPopoverOpen,
|
||||
onOpenChange: setFreeTrialPopoverOpen,
|
||||
onOpenChange: handleFreeTrialPopoverOpenChange,
|
||||
triggerContent: localFreeTrialDisplayText,
|
||||
popoverContent: (
|
||||
<div className="space-y-3">
|
||||
@ -795,7 +811,7 @@ function ProductDetailsSection({ productId, product, config }: ProductDetailsSec
|
||||
type="number"
|
||||
min={1}
|
||||
value={freeTrialCount}
|
||||
onChange={(e) => setFreeTrialCount(parseInt(e.target.value) || 1)}
|
||||
onChange={(e) => setFreeTrialCount(Math.max(1, parseInt(e.target.value) || 1))}
|
||||
/>
|
||||
<DesignSelectorDropdown
|
||||
className="w-28"
|
||||
|
||||
@ -296,7 +296,9 @@ function EditableTextField({
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" && !event.nativeEvent.isComposing) {
|
||||
event.preventDefault();
|
||||
runAsynchronouslyWithAlert(save());
|
||||
if (draftValue !== item.value && !isSaving) {
|
||||
runAsynchronouslyWithAlert(save());
|
||||
}
|
||||
}
|
||||
if (event.key === "Escape") {
|
||||
cancelEditing();
|
||||
@ -598,10 +600,10 @@ function ItemValue({
|
||||
}
|
||||
case "custom-button": {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
<DesignButton
|
||||
variant="plain"
|
||||
disabled={item.disabled}
|
||||
onClick={() => runAsynchronouslyWithAlert(item.onClick())}
|
||||
onClick={() => item.onClick()}
|
||||
className={cn(
|
||||
"flex w-full items-center justify-start gap-2 text-left font-normal",
|
||||
size.controlHeight,
|
||||
@ -609,11 +611,10 @@ function ItemValue({
|
||||
size.controlText,
|
||||
designEditableGridControlClassName,
|
||||
editMode && "border-black/[0.18] dark:border-white/[0.22]",
|
||||
item.disabled && "cursor-not-allowed opacity-50",
|
||||
)}
|
||||
>
|
||||
<span className="min-w-0 truncate">{item.children}</span>
|
||||
</button>
|
||||
</DesignButton>
|
||||
);
|
||||
}
|
||||
case "custom": {
|
||||
@ -673,6 +674,17 @@ function SaveBar({
|
||||
onDiscard: () => void,
|
||||
onSave: () => Promise<void>,
|
||||
}) {
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const handleSave = async () => {
|
||||
setIsSaving(true);
|
||||
try {
|
||||
await onSave();
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
aria-live="polite"
|
||||
@ -685,13 +697,19 @@ function SaveBar({
|
||||
<div className="flex items-center justify-end gap-1.5">
|
||||
<DesignButton
|
||||
className="h-8 rounded-lg px-3 text-xs text-muted-foreground"
|
||||
disabled={isSaving}
|
||||
onClick={onDiscard}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
>
|
||||
Discard
|
||||
</DesignButton>
|
||||
<DesignButton className="h-8 rounded-lg px-3 text-xs" onClick={onSave} size="sm">
|
||||
<DesignButton
|
||||
className="h-8 rounded-lg px-3 text-xs"
|
||||
loading={isSaving}
|
||||
onClick={handleSave}
|
||||
size="sm"
|
||||
>
|
||||
Save changes
|
||||
</DesignButton>
|
||||
</div>
|
||||
@ -734,7 +752,7 @@ export function DesignEditableGrid({
|
||||
"grid items-center text-sm",
|
||||
resolvedSize.gapX,
|
||||
resolvedSize.gapY,
|
||||
columns === 2 && "lg:[&>*:nth-child(4n+3)]:pl-4",
|
||||
columns === 2 && "lg:[&>div:nth-child(even)>:first-child]:pl-4",
|
||||
gridCols,
|
||||
className,
|
||||
)}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user