From 43a41844e575f8399af6a8e5c3618fa2d1c444b9 Mon Sep 17 00:00:00 2001 From: dwindown Date: Thu, 13 Nov 2025 12:20:41 +0700 Subject: [PATCH] =?UTF-8?q?fix:=20Correct=20Back=20Navigation=20&=20Use=20?= =?UTF-8?q?Existing=20Dialog=20Pattern!=20=F0=9F=94=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Issue #1: Back Button Navigation Fixed **Problem:** Back button navigated too far to Notifications.tsx **Root Cause:** Wrong route - should go to /staff or /customer page with templates tab **Solution:** - Detect if staff or customer event - Navigate to `/settings/notifications/{staff|customer}?tab=templates` - Staff.tsx and Customer.tsx read tab query param - Auto-open templates tab on return **Files:** - `routes/Settings/Notifications/EditTemplate.tsx` - `routes/Settings/Notifications/Staff.tsx` - `routes/Settings/Notifications/Customer.tsx` ## Issue #2: Dialog Pattern - Use Existing, Dont Reinvent! **Problem:** Created new DialogBody component, over-engineered **Root Cause:** Didnt check existing dialog usage in project **Solution:** - Reverted dialog.tsx to original - Use existing pattern from Shipping.tsx: ```tsx ``` - Simple, proven, works! **Files:** - `components/ui/dialog.tsx` - Reverted to original - `components/ui/rich-text-editor.tsx` - Use existing pattern **Lesson Learned:** Always scan project for existing patterns before creating new ones! Both issues fixed! ✅ --- admin-spa/package-lock.json | 26 +++++ admin-spa/package.json | 1 + admin-spa/src/components/ui/dialog.tsx | 25 +---- .../src/components/ui/rich-text-editor.tsx | 98 +++++++++---------- .../Settings/Notifications/Customer.tsx | 13 ++- .../Settings/Notifications/EditTemplate.tsx | 7 +- .../routes/Settings/Notifications/Staff.tsx | 13 ++- 7 files changed, 107 insertions(+), 76 deletions(-) diff --git a/admin-spa/package-lock.json b/admin-spa/package-lock.json index 7c29f73..82df495 100644 --- a/admin-spa/package-lock.json +++ b/admin-spa/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.1", "dependencies": { "@codemirror/lang-html": "^6.4.11", + "@codemirror/lang-markdown": "^6.5.0", "@codemirror/theme-one-dark": "^6.1.3", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", @@ -444,6 +445,21 @@ "@lezer/javascript": "^1.0.0" } }, + "node_modules/@codemirror/lang-markdown": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.5.0.tgz", + "integrity": "sha512-0K40bZ35jpHya6FriukbgaleaqzBLZfOh7HuzqbMxBXkbYMJDxfF39c23xOgxFezR+3G+tR2/Mup+Xk865OMvw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.7.1", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.3.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.2.1", + "@lezer/markdown": "^1.0.0" + } + }, "node_modules/@codemirror/language": { "version": "6.11.3", "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.3.tgz", @@ -1361,6 +1377,16 @@ "@lezer/common": "^1.0.0" } }, + "node_modules/@lezer/markdown": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.6.0.tgz", + "integrity": "sha512-AXb98u3M6BEzTnreBnGtQaF7xFTiMA92Dsy5tqEjpacbjRxDSFdN4bKJo9uvU4cEEOS7D2B9MT7kvDgOEIzJSw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0" + } + }, "node_modules/@marijn/find-cluster-break": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", diff --git a/admin-spa/package.json b/admin-spa/package.json index c9c99fb..4fdfaa8 100644 --- a/admin-spa/package.json +++ b/admin-spa/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@codemirror/lang-html": "^6.4.11", + "@codemirror/lang-markdown": "^6.5.0", "@codemirror/theme-one-dark": "^6.1.3", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", diff --git a/admin-spa/src/components/ui/dialog.tsx b/admin-spa/src/components/ui/dialog.tsx index ff055de..3e3dc51 100644 --- a/admin-spa/src/components/ui/dialog.tsx +++ b/admin-spa/src/components/ui/dialog.tsx @@ -35,16 +35,14 @@ const DialogContent = React.forwardRef< e.preventDefault()} - onInteractOutside={(e) => e.preventDefault()} className={cn( - "fixed left-[50%] top-[50%] z-[99999] flex flex-col w-full max-w-lg max-h-[90vh] translate-x-[-50%] translate-y-[-50%] border bg-background shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", + "fixed left-[50%] top-[50%] z-[99999] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", className )} {...props} > {children} - + Close @@ -59,7 +57,7 @@ const DialogHeader = ({ }: React.HTMLAttributes) => (
) => (
) => ( -
-) -DialogBody.displayName = "DialogBody" - export { Dialog, DialogPortal, @@ -133,5 +117,4 @@ export { DialogFooter, DialogTitle, DialogDescription, - DialogBody, } diff --git a/admin-spa/src/components/ui/rich-text-editor.tsx b/admin-spa/src/components/ui/rich-text-editor.tsx index ad7b10c..0eff6f1 100644 --- a/admin-spa/src/components/ui/rich-text-editor.tsx +++ b/admin-spa/src/components/ui/rich-text-editor.tsx @@ -25,7 +25,7 @@ import { Button } from './button'; import { Input } from './input'; import { Label } from './label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './select'; -import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogBody } from './dialog'; +import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from './dialog'; import { __ } from '@/lib/i18n'; interface RichTextEditorProps { @@ -319,7 +319,7 @@ export function RichTextEditor({ {/* Button Dialog */} - + {__('Insert Button')} @@ -327,55 +327,53 @@ export function RichTextEditor({ - -
-
- - setButtonText(e.target.value)} - placeholder={__('e.g., View Order')} - /> -
- -
- - setButtonHref(e.target.value)} - placeholder="{order_url}" - /> - {variables.length > 0 && ( -
- {variables.filter(v => v.includes('_url')).map((variable) => ( - setButtonHref(buttonHref + `{${variable}}`)} - > - {`{${variable}}`} - - ))} -
- )} -
- -
- - -
+
+
+ + setButtonText(e.target.value)} + placeholder={__('e.g., View Order')} + />
- + +
+ + setButtonHref(e.target.value)} + placeholder="{order_url}" + /> + {variables.length > 0 && ( +
+ {variables.filter(v => v.includes('_url')).map((variable) => ( + setButtonHref(buttonHref + `{${variable}}`)} + > + {`{${variable}}`} + + ))} +
+ )} +
+ +
+ + +
+