fix: Submenu active state + currency symbols + flags integration

1. Fixed Submenu Active State 
   Problem: First submenu always active due to pathname.startsWith()
   - /dashboard matches /dashboard/analytics
   - Both items show as active

   Solution: Use exact match instead
   - const isActive = pathname === it.path
   - Only clicked item shows as active

   Files: DashboardSubmenuBar.tsx, SubmenuBar.tsx

2. Fixed Currency Symbol Display 
   Problem: HTML entities showing (ءإ)
   Solution: Use currency code when symbol has HTML entities

   Before: United Arab Emirates dirham (ءإ)
   After: United Arab Emirates dirham (AED)

   Logic:
   const displaySymbol = (!currency.symbol || currency.symbol.includes('&#'))
     ? currency.code
     : currency.symbol;

3. Integrated Flags.json 

   A. Moved flags.json to admin-spa/src/data/
   B. Added flag support to SearchableSelect component
      - New icon prop in Option interface
      - Displays flag before label in trigger
      - Displays flag before label in dropdown

   C. Currency select now shows flags
      - Flag icon next to each currency
      - Visual country identification
      - Better UX for currency selection

   D. Dynamic store summary with flag
      Before: 🇮🇩 Your store is located in Indonesia
      After: [FLAG] Your store is located in Indonesia

      - Flag based on selected currency
      - Country name from flags.json
      - Currency name (not just code)
      - Dynamic updates when currency changes

Benefits:
 Clear submenu navigation
 Readable currency symbols
 Visual country flags
 Better currency selection UX
 Dynamic store location display

Files Modified:
- DashboardSubmenuBar.tsx: Exact match for active state
- SubmenuBar.tsx: Exact match for active state
- Store.tsx: Currency symbol fix + flags integration
- searchable-select.tsx: Icon support
- flags.json: Moved to admin-spa/src/data/
This commit is contained in:
dwindown
2025-11-06 11:35:32 +07:00
parent cd644d339c
commit 2a679ffd15
9 changed files with 2276 additions and 36 deletions

View File

@@ -22,6 +22,8 @@ export interface Option {
label: React.ReactNode;
/** Optional text used for filtering. Falls back to string label or value. */
searchText?: string;
/** Optional icon (base64 image or URL) to display before the label */
icon?: string;
}
interface Props {
@@ -65,7 +67,12 @@ export function SearchableSelect({
aria-disabled={disabled}
tabIndex={disabled ? -1 : 0}
>
{selected ? selected.label : placeholder}
<div className="flex items-center gap-2 flex-1 min-w-0">
{selected?.icon && (
<img src={selected.icon} alt="" className="w-5 h-4 object-cover rounded-sm flex-shrink-0" />
)}
<span className="truncate">{selected ? selected.label : placeholder}</span>
</div>
<ChevronsUpDown className="opacity-50 h-4 w-4 shrink-0" />
</Button>
</PopoverTrigger>
@@ -99,12 +106,15 @@ export function SearchableSelect({
{showCheckIndicator && (
<Check
className={cn(
"mr-2 h-4 w-4",
"mr-2 h-4 w-4 flex-shrink-0",
opt.value === value ? "opacity-100" : "opacity-0"
)}
/>
)}
{opt.label}
{opt.icon && (
<img src={opt.icon} alt="" className="w-5 h-4 object-cover rounded-sm mr-2 flex-shrink-0" />
)}
<span className="truncate">{opt.label}</span>
</CommandItem>
))}
</CommandList>