feat: Convert Products form to vertical tab layout
Applied VerticalTabForm to ProductFormTabbed Changes: 1. Replaced horizontal Tabs with VerticalTabForm 2. Converted TabsContent to FormSection components 3. Removed activeTab state (scroll spy handles this) 4. Dynamic tabs based on product type - Simple: General, Inventory, Organization - Variable: General, Inventory, Variations, Organization Benefits: ✅ Consistent layout with Coupons form ✅ Better space utilization ✅ Narrower content area (more readable) ✅ Scroll spy navigation ✅ Click to scroll to section ✅ Professional UI Layout: - Desktop: 250px sidebar + content area - Sidebar: Sticky with icons - Content: Scrollable with smooth navigation - Mobile: Keeps original horizontal tabs (future) Removed: - TabsList, TabsTrigger components - activeTab state and setActiveTab calls - Manual tab switching on validation errors Result: Both Products and Coupons now use same vertical tab pattern Forms are more professional and easier to navigate
This commit is contained in:
@@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query';
|
|||||||
import { api } from '@/lib/api';
|
import { api } from '@/lib/api';
|
||||||
import { __ } from '@/lib/i18n';
|
import { __ } from '@/lib/i18n';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
import { VerticalTabForm, FormSection } from '@/components/VerticalTabForm';
|
||||||
import { Package, DollarSign, Layers, Tag } from 'lucide-react';
|
import { Package, DollarSign, Layers, Tag } from 'lucide-react';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { GeneralTab } from './tabs/GeneralTab';
|
import { GeneralTab } from './tabs/GeneralTab';
|
||||||
@@ -74,7 +74,6 @@ export function ProductFormTabbed({
|
|||||||
const [downloadable, setDownloadable] = useState(initial?.downloadable || false);
|
const [downloadable, setDownloadable] = useState(initial?.downloadable || false);
|
||||||
const [featured, setFeatured] = useState(initial?.featured || false);
|
const [featured, setFeatured] = useState(initial?.featured || false);
|
||||||
const [submitting, setSubmitting] = useState(false);
|
const [submitting, setSubmitting] = useState(false);
|
||||||
const [activeTab, setActiveTab] = useState('general');
|
|
||||||
|
|
||||||
// Update form state when initial data changes (for edit mode)
|
// Update form state when initial data changes (for edit mode)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -124,13 +123,11 @@ export function ProductFormTabbed({
|
|||||||
// Validation
|
// Validation
|
||||||
if (!name.trim()) {
|
if (!name.trim()) {
|
||||||
toast.error(__('Product name is required'));
|
toast.error(__('Product name is required'));
|
||||||
setActiveTab('general');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'simple' && !regularPrice) {
|
if (type === 'simple' && !regularPrice) {
|
||||||
toast.error(__('Regular price is required for simple products'));
|
toast.error(__('Regular price is required for simple products'));
|
||||||
setActiveTab('general');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,32 +163,19 @@ export function ProductFormTabbed({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Define tabs based on product type
|
||||||
|
const tabs = [
|
||||||
|
{ id: 'general', label: __('General'), icon: <Package className="w-4 h-4" /> },
|
||||||
|
{ id: 'inventory', label: __('Inventory'), icon: <Layers className="w-4 h-4" /> },
|
||||||
|
...(type === 'variable' ? [{ id: 'variations', label: __('Variations'), icon: <Layers className="w-4 h-4" /> }] : []),
|
||||||
|
{ id: 'organization', label: __('Organization'), icon: <Tag className="w-4 h-4" /> },
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form ref={formRef} onSubmit={handleSubmit} className={className}>
|
<form ref={formRef} onSubmit={handleSubmit} className={className}>
|
||||||
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
|
<VerticalTabForm tabs={tabs}>
|
||||||
<TabsList className={`grid w-full mb-6 ${type === 'variable' ? 'grid-cols-4' : 'grid-cols-3'}`}>
|
|
||||||
<TabsTrigger value="general" className="flex items-center gap-2">
|
|
||||||
<Package className="w-4 h-4" />
|
|
||||||
<span className="hidden sm:inline">{__('General')}</span>
|
|
||||||
</TabsTrigger>
|
|
||||||
<TabsTrigger value="inventory" className="flex items-center gap-2">
|
|
||||||
<Layers className="w-4 h-4" />
|
|
||||||
<span className="hidden sm:inline">{__('Inventory')}</span>
|
|
||||||
</TabsTrigger>
|
|
||||||
{type === 'variable' && (
|
|
||||||
<TabsTrigger value="variations" className="flex items-center gap-2">
|
|
||||||
<Layers className="w-4 h-4" />
|
|
||||||
<span className="hidden sm:inline">{__('Variations')}</span>
|
|
||||||
</TabsTrigger>
|
|
||||||
)}
|
|
||||||
<TabsTrigger value="organization" className="flex items-center gap-2">
|
|
||||||
<Tag className="w-4 h-4" />
|
|
||||||
<span className="hidden sm:inline">{__('Organization')}</span>
|
|
||||||
</TabsTrigger>
|
|
||||||
</TabsList>
|
|
||||||
|
|
||||||
{/* General Tab */}
|
{/* General Tab */}
|
||||||
<TabsContent value="general">
|
<FormSection id="general">
|
||||||
<GeneralTab
|
<GeneralTab
|
||||||
name={name}
|
name={name}
|
||||||
setName={setName}
|
setName={setName}
|
||||||
@@ -216,10 +200,10 @@ export function ProductFormTabbed({
|
|||||||
salePrice={salePrice}
|
salePrice={salePrice}
|
||||||
setSalePrice={setSalePrice}
|
setSalePrice={setSalePrice}
|
||||||
/>
|
/>
|
||||||
</TabsContent>
|
</FormSection>
|
||||||
|
|
||||||
{/* Inventory Tab */}
|
{/* Inventory Tab */}
|
||||||
<TabsContent value="inventory">
|
<FormSection id="inventory">
|
||||||
<InventoryTab
|
<InventoryTab
|
||||||
manageStock={manageStock}
|
manageStock={manageStock}
|
||||||
setManageStock={setManageStock}
|
setManageStock={setManageStock}
|
||||||
@@ -228,21 +212,23 @@ export function ProductFormTabbed({
|
|||||||
stockStatus={stockStatus || 'instock'}
|
stockStatus={stockStatus || 'instock'}
|
||||||
setStockStatus={setStockStatus}
|
setStockStatus={setStockStatus}
|
||||||
/>
|
/>
|
||||||
</TabsContent>
|
</FormSection>
|
||||||
|
|
||||||
{/* Variations Tab */}
|
{/* Variations Tab (only for variable products) */}
|
||||||
<TabsContent value="variations">
|
{type === 'variable' && (
|
||||||
<VariationsTab
|
<FormSection id="variations">
|
||||||
attributes={attributes}
|
<VariationsTab
|
||||||
setAttributes={setAttributes}
|
attributes={attributes}
|
||||||
variations={variations}
|
setAttributes={setAttributes}
|
||||||
setVariations={setVariations}
|
variations={variations}
|
||||||
regularPrice={regularPrice}
|
setVariations={setVariations}
|
||||||
/>
|
regularPrice={regularPrice}
|
||||||
</TabsContent>
|
/>
|
||||||
|
</FormSection>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Organization Tab */}
|
{/* Organization Tab */}
|
||||||
<TabsContent value="organization">
|
<FormSection id="organization">
|
||||||
<OrganizationTab
|
<OrganizationTab
|
||||||
categories={categories}
|
categories={categories}
|
||||||
selectedCategories={selectedCategories}
|
selectedCategories={selectedCategories}
|
||||||
@@ -251,17 +237,21 @@ export function ProductFormTabbed({
|
|||||||
selectedTags={selectedTags}
|
selectedTags={selectedTags}
|
||||||
setSelectedTags={setSelectedTags}
|
setSelectedTags={setSelectedTags}
|
||||||
/>
|
/>
|
||||||
</TabsContent>
|
</FormSection>
|
||||||
</Tabs>
|
|
||||||
|
|
||||||
{/* Submit Button */}
|
{/* Submit Button */}
|
||||||
{!hideSubmitButton && (
|
{!hideSubmitButton && (
|
||||||
<div className="flex justify-end gap-3 pt-6 border-t mt-6">
|
<div className="mt-6 flex gap-3">
|
||||||
<Button type="submit" disabled={submitting}>
|
<Button type="submit" disabled={submitting}>
|
||||||
{submitting ? __('Saving...') : mode === 'create' ? __('Create Product') : __('Update Product')}
|
{submitting
|
||||||
</Button>
|
? __('Saving...')
|
||||||
</div>
|
: mode === 'create'
|
||||||
)}
|
? __('Create Product')
|
||||||
|
: __('Update Product')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</VerticalTabForm>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user