fix: Edit route, price input alignment, and currency in variations
Fixed 3 issues: 1. Edit Page Route - FIXED Problem: URL shows /products/332/edit but page says "New Product" Root Cause: Route pointing to wrong component App.tsx changes: - Import ProductEdit component - Fix route: /products/:id/edit → ProductEdit (was ProductNew) - Remove duplicate /products/:id route Result: - Edit page now shows "Edit Product" title - Product data loads correctly - Proper page header and actions 2. Price Input Alignment - FIXED Problem: Currency symbol overlaps input, no right-align GeneralTab.tsx: - Changed pl-10 → pl-9 (better padding for symbol) - Added pr-3 (right padding) - Added text-right (right-align numbers) VariationsTab.tsx: - Wrapped price inputs in relative div - Added currency symbol span - Applied pl-8 pr-3 text-right - Use store.decimals for step (1 or 0.01) Result: - Currency symbol visible without overlap - Numbers right-aligned (better UX) - Proper spacing - Works for all currencies (Rp, $, RM, etc.) 3. Categories/Tags Management - NOTED Current: Can only select existing categories/tags Solution: Users should manage in Categories and Tags tabs Future: Could add inline create with + button For now: Use dedicated tabs to add new categories/tags Result: - Edit page works correctly - Price inputs look professional - Currency support complete - Clear workflow for categories/tags
This commit is contained in:
@@ -14,6 +14,7 @@ import OrderEdit from '@/routes/Orders/Edit';
|
|||||||
import OrderDetail from '@/routes/Orders/Detail';
|
import OrderDetail from '@/routes/Orders/Detail';
|
||||||
import ProductsIndex from '@/routes/Products';
|
import ProductsIndex from '@/routes/Products';
|
||||||
import ProductNew from '@/routes/Products/New';
|
import ProductNew from '@/routes/Products/New';
|
||||||
|
import ProductEdit from '@/routes/Products/Edit';
|
||||||
import ProductCategories from '@/routes/Products/Categories';
|
import ProductCategories from '@/routes/Products/Categories';
|
||||||
import ProductTags from '@/routes/Products/Tags';
|
import ProductTags from '@/routes/Products/Tags';
|
||||||
import ProductAttributes from '@/routes/Products/Attributes';
|
import ProductAttributes from '@/routes/Products/Attributes';
|
||||||
@@ -462,8 +463,7 @@ function AppRoutes() {
|
|||||||
{/* Products */}
|
{/* Products */}
|
||||||
<Route path="/products" element={<ProductsIndex />} />
|
<Route path="/products" element={<ProductsIndex />} />
|
||||||
<Route path="/products/new" element={<ProductNew />} />
|
<Route path="/products/new" element={<ProductNew />} />
|
||||||
<Route path="/products/:id/edit" element={<ProductNew />} />
|
<Route path="/products/:id/edit" element={<ProductEdit />} />
|
||||||
<Route path="/products/:id" element={<ProductNew />} />
|
|
||||||
<Route path="/products/categories" element={<ProductCategories />} />
|
<Route path="/products/categories" element={<ProductCategories />} />
|
||||||
<Route path="/products/tags" element={<ProductTags />} />
|
<Route path="/products/tags" element={<ProductTags />} />
|
||||||
<Route path="/products/attributes" element={<ProductAttributes />} />
|
<Route path="/products/attributes" element={<ProductAttributes />} />
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ export function GeneralTab({
|
|||||||
onChange={(e) => setRegularPrice(e.target.value)}
|
onChange={(e) => setRegularPrice(e.target.value)}
|
||||||
placeholder={store.decimals === 0 ? '0' : '0.00'}
|
placeholder={store.decimals === 0 ? '0' : '0.00'}
|
||||||
required={type === 'simple'}
|
required={type === 'simple'}
|
||||||
className="pl-10"
|
className="pl-9 pr-3 text-right"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-muted-foreground mt-1">
|
<p className="text-xs text-muted-foreground mt-1">
|
||||||
@@ -225,7 +225,7 @@ export function GeneralTab({
|
|||||||
value={salePrice}
|
value={salePrice}
|
||||||
onChange={(e) => setSalePrice(e.target.value)}
|
onChange={(e) => setSalePrice(e.target.value)}
|
||||||
placeholder={store.decimals === 0 ? '0' : '0.00'}
|
placeholder={store.decimals === 0 ? '0' : '0.00'}
|
||||||
className="pl-10"
|
className="pl-9 pr-3 text-right"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-muted-foreground mt-1">
|
<p className="text-xs text-muted-foreground mt-1">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { __ } from '@/lib/i18n';
|
import { __ } from '@/lib/i18n';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
@@ -9,6 +9,7 @@ import { Badge } from '@/components/ui/badge';
|
|||||||
import { Separator } from '@/components/ui/separator';
|
import { Separator } from '@/components/ui/separator';
|
||||||
import { Plus, X, Layers } from 'lucide-react';
|
import { Plus, X, Layers } from 'lucide-react';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
|
import { getStoreCurrency } from '@/lib/currency';
|
||||||
|
|
||||||
export type ProductVariant = {
|
export type ProductVariant = {
|
||||||
id?: number;
|
id?: number;
|
||||||
@@ -36,6 +37,8 @@ export function VariationsTab({
|
|||||||
setVariations,
|
setVariations,
|
||||||
regularPrice,
|
regularPrice,
|
||||||
}: VariationsTabProps) {
|
}: VariationsTabProps) {
|
||||||
|
const store = getStoreCurrency();
|
||||||
|
|
||||||
const addAttribute = () => {
|
const addAttribute = () => {
|
||||||
setAttributes([...attributes, { name: '', options: [], variation: false }]);
|
setAttributes([...attributes, { name: '', options: [], variation: false }]);
|
||||||
};
|
};
|
||||||
@@ -217,28 +220,40 @@ export function VariationsTab({
|
|||||||
setVariations(updated);
|
setVariations(updated);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Input
|
<div className="relative">
|
||||||
type="number"
|
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-xs text-muted-foreground font-medium">
|
||||||
step="0.01"
|
{store.symbol}
|
||||||
placeholder={__('Price')}
|
</span>
|
||||||
value={variation.regular_price || ''}
|
<Input
|
||||||
onChange={(e) => {
|
type="number"
|
||||||
const updated = [...variations];
|
step={store.decimals === 0 ? '1' : '0.01'}
|
||||||
updated[index].regular_price = e.target.value;
|
placeholder={__('Price')}
|
||||||
setVariations(updated);
|
value={variation.regular_price || ''}
|
||||||
}}
|
onChange={(e) => {
|
||||||
/>
|
const updated = [...variations];
|
||||||
<Input
|
updated[index].regular_price = e.target.value;
|
||||||
type="number"
|
setVariations(updated);
|
||||||
step="0.01"
|
}}
|
||||||
placeholder={__('Sale')}
|
className="pl-8 pr-3 text-right"
|
||||||
value={variation.sale_price || ''}
|
/>
|
||||||
onChange={(e) => {
|
</div>
|
||||||
const updated = [...variations];
|
<div className="relative">
|
||||||
updated[index].sale_price = e.target.value;
|
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-xs text-muted-foreground font-medium">
|
||||||
setVariations(updated);
|
{store.symbol}
|
||||||
}}
|
</span>
|
||||||
/>
|
<Input
|
||||||
|
type="number"
|
||||||
|
step={store.decimals === 0 ? '1' : '0.01'}
|
||||||
|
placeholder={__('Sale')}
|
||||||
|
value={variation.sale_price || ''}
|
||||||
|
onChange={(e) => {
|
||||||
|
const updated = [...variations];
|
||||||
|
updated[index].sale_price = e.target.value;
|
||||||
|
setVariations(updated);
|
||||||
|
}}
|
||||||
|
className="pl-8 pr-3 text-right"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
placeholder={__('Stock')}
|
placeholder={__('Stock')}
|
||||||
|
|||||||
Reference in New Issue
Block a user