Skip to content
Merged
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
7 changes: 7 additions & 0 deletions app/ui/src/app/edit/components/address/AddressOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ type AddressOverlayProps = {
initialAddress?: Partial<LocationAddress>;
onClose: () => void;
onSave: (address: LocationAddress) => void;
primaryDisabled?: boolean;
};

export default function AddressOverlay({
Expand All @@ -99,6 +100,7 @@ export default function AddressOverlay({
initialAddress,
onClose,
onSave,
primaryDisabled = false,
}: AddressOverlayProps) {
const panelRef = useFocusTrap<HTMLDivElement>(true);

Expand All @@ -109,6 +111,7 @@ export default function AddressOverlay({
const [zipCode, setZipCode] = useState(initialAddress?.zipCode ?? "");
const [country, setCountry] = useState(initialAddress?.country ?? "");
const [submitted, setSubmitted] = useState(false);
const [saveStarted, setSaveStarted] = useState(false);

const line1InputRef = useRef<HTMLInputElement>(null);
const blurTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
Expand Down Expand Up @@ -177,6 +180,7 @@ export default function AddressOverlay({
}

function handleSave() {
if (saveStarted || primaryDisabled) return;
setSubmitted(true);
const trimmedLine1 = line1.trim();
const trimmedCity = city.trim();
Expand All @@ -188,6 +192,7 @@ export default function AddressOverlay({
!country
)
return;
setSaveStarted(true);
onSave({
line1: trimmedLine1,
line2: line2.trim(),
Expand Down Expand Up @@ -442,6 +447,8 @@ export default function AddressOverlay({
type="button"
onClick={handleSave}
className={`${OVERLAY_PRIMARY_BTN} ${styles.primaryBtnOverlay}`}
disabled={primaryDisabled || saveStarted}
aria-busy={primaryDisabled || saveStarted}
>
{primaryLabel}
</button>
Expand Down
4 changes: 2 additions & 2 deletions app/ui/src/app/edit/components/address/CSVUploadOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
CSV_UPLOAD_FILE_CHIP_SIZE,
CSV_UPLOAD_FILE_CHIP_REMOVE,
} from "@/app/edit/formStyles.v2";
import ErrorOverlay from "@/app/edit/components/shared/ErrorOverlay";
import AlertPopup from "@/app/edit/components/shared/AlertPopup";
import type { AddressCard } from "@/app/edit/types/delivery";
import { useCSVImport } from "@/app/edit/hooks/useCSVImport";

Expand Down Expand Up @@ -666,7 +666,7 @@ export default function CSVUploadOverlay({
// ── Render ──────────────────────────────────────────────────────────────────

if (parseError) {
return <ErrorOverlay message={parseError} onClose={closeImportModal} />;
return <AlertPopup message={parseError} onClose={closeImportModal} />;
}

if (isImportModalOpen) {
Expand Down
115 changes: 115 additions & 0 deletions app/ui/src/app/edit/components/shared/AlertPopup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
"use client";

import { type KeyboardEvent, useId } from "react";

import {
ALERT_POPUP_FOOTER,
ALERT_POPUP_MESSAGE,
OVERLAY_BACKDROP,
OVERLAY_CANCEL_BTN,
OVERLAY_CLOSE_BTN,
OVERLAY_HEADER,
OVERLAY_PANEL,
OVERLAY_PRIMARY_BTN,
OVERLAY_TITLE,
OVERLAY_WARNING_BTN,
} from "@/app/edit/formStyles.v2";
import styles from "@/app/edit/edit.module.css";
import { useFocusTrap } from "@/app/edit/hooks/useFocusTrap";

export type AlertPopupVariant = "error" | "warning";

type AlertPopupProps = {
message: string | null;
onClose: () => void;
variant?: AlertPopupVariant;
title?: string;
action?: {
label: string;
onClick: () => void;
};
actionDisabled?: boolean;
};

export default function AlertPopup({
message,
onClose,
variant = "error",
title = variant === "warning" ? "Warning" : "Something went wrong",
action,
actionDisabled = false,
}: AlertPopupProps) {
const panelRef = useFocusTrap<HTMLDivElement>(!!message);
const titleId = useId();
const messageId = useId();

function handleKeyDown(event: KeyboardEvent): void {
if (event.key === "Escape") {
onClose();
}
}

if (!message) return null;

return (
<div className={OVERLAY_BACKDROP} onKeyDown={handleKeyDown}>
<div
ref={panelRef}
className={OVERLAY_PANEL}
role={action ? "alertdialog" : "dialog"}
aria-modal={true}
aria-labelledby={titleId}
aria-describedby={messageId}
>
<div className={OVERLAY_HEADER}>
<h2 id={titleId} className={OVERLAY_TITLE}>
{title}
</h2>
<button
type="button"
onClick={onClose}
className={OVERLAY_CLOSE_BTN}
aria-label={`Close ${title}`}
>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
aria-hidden={true}
>
<line x1="18" y1="6" x2="6" y2="18" />
<line x1="6" y1="6" x2="18" y2="18" />
</svg>
</button>
</div>
<p id={messageId} className={ALERT_POPUP_MESSAGE}>
{message}
</p>
<div className={ALERT_POPUP_FOOTER}>
{action && (
<button
type="button"
onClick={onClose}
className={OVERLAY_CANCEL_BTN}
>
Cancel
</button>
)}
<button
type="button"
onClick={action?.onClick ?? onClose}
className={`${variant === "warning" ? OVERLAY_WARNING_BTN : OVERLAY_PRIMARY_BTN} ${styles.primaryBtnOverlay}`}
disabled={action ? actionDisabled : false}
aria-busy={action ? actionDisabled : false}
>
{action?.label ?? "Dismiss"}
</button>
</div>
</div>
</div>
);
}
79 changes: 0 additions & 79 deletions app/ui/src/app/edit/components/shared/ErrorOverlay.tsx

This file was deleted.

1 change: 1 addition & 0 deletions app/ui/src/app/edit/edit.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* <div className={styles.root}>...</div>
*/

/* Page wrapper class; --edit-* button tokens live on :root in globals.css. */
.root {
}

Expand Down
11 changes: 7 additions & 4 deletions app/ui/src/app/edit/formStyles.v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,10 @@ export const OVERLAY_CANCEL_BTN =
"h-9 px-4 rounded-[80px] font-semibold text-[14px] leading-5 text-[var(--edit-text-primary)] whitespace-nowrap hover:bg-[var(--edit-tertiary-btn-hover)] active:bg-[var(--edit-tertiary-btn-pressed)] transition-colors cursor-pointer";

export const OVERLAY_PRIMARY_BTN =
"h-9 px-4 rounded-[80px] bg-[var(--edit-btn-primary)] font-semibold text-[14px] leading-5 text-[var(--edit-text-primary)] whitespace-nowrap cursor-pointer";
"h-9 px-4 rounded-[80px] bg-[var(--edit-btn-primary)] font-semibold text-[14px] leading-5 text-[var(--edit-text-primary)] whitespace-nowrap cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed";

export const OVERLAY_WARNING_BTN =
"h-9 px-4 rounded-[80px] bg-[var(--edit-btn-warning)] font-semibold text-[14px] leading-5 text-[var(--edit-text-primary)] whitespace-nowrap cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed";

export const OVERLAY_DELETE_BTN =
"h-9 px-4 rounded-[80px] bg-[var(--edit-btn-delete)] font-semibold text-[14px] leading-5 text-[var(--edit-text-invert)] whitespace-nowrap cursor-pointer";
Expand Down Expand Up @@ -780,12 +783,12 @@ export const MOBILE_BOTTOM_BAR_SECONDARY_BTN =
export const MOBILE_BOTTOM_BAR_SECONDARY_LABEL =
"font-['Manrope',sans-serif] font-semibold text-[16px] leading-[22px] text-[var(--edit-text-primary)] whitespace-nowrap";

// ── ErrorOverlay ──────────────────────────────────────────────────────────────
// ── AlertPopup ────────────────────────────────────────────────────────────────

export const ERROR_OVERLAY_MESSAGE =
export const ALERT_POPUP_MESSAGE =
"text-[14px] leading-5 text-[var(--edit-text-secondary)] w-full";

export const ERROR_OVERLAY_FOOTER = "flex items-center justify-end";
export const ALERT_POPUP_FOOTER = "flex items-center justify-end gap-2";

// ── CSV Upload Overlay (Figma 8102:1548 desktop / 7472:5765 mobile) ───────────

Expand Down
Loading
Loading