Added functionality in Attribute step of product creation configuration

This commit is contained in:
Mahir-Mohamed
2026-08-11 11:01:34 +05:30
parent d04610f1ac
commit f012aa37e9
4 changed files with 1720 additions and 1586 deletions
@@ -32,6 +32,7 @@ interface DynamicAttributesSectionProps {
errors?: Record<string, any>;
touched?: Record<string, any>;
onAttributeChange: (code: string, value: any) => void;
onAddAttributeClick?: (group: any) => void;
readOnly?: boolean;
}
@@ -42,6 +43,7 @@ export const DynamicAttributesSection: React.FC<DynamicAttributesSectionProps> =
errors = {},
touched = {},
onAttributeChange,
onAddAttributeClick,
readOnly,
}) => {
if (!hasAttributeSet) {
@@ -89,6 +91,7 @@ export const DynamicAttributesSection: React.FC<DynamicAttributesSectionProps> =
errors={errors}
touched={touched}
onAttributeChange={onAttributeChange}
onAddAttributeClick={onAddAttributeClick}
readOnly={readOnly}
/>
))}
@@ -3,7 +3,7 @@ import { assetsService, type AssetMapping } from '../../assets/services/assets.s
import type { Asset } from '../../assets/types/assets.types';
import {
Upload, Image as ImageIcon, Video, FileText, Trash2,
Check, Loader2, Search, Info, Shield, ArrowUp, ArrowDown
Check, Loader2, Search, Info, Shield, ArrowUp, ArrowDown, Plus
} from 'lucide-react';
import { toast } from 'react-toastify';
import { Loader } from '../../../components/customs/Loader';
@@ -87,6 +87,36 @@ export const ProductAssetsTab: React.FC<ProductAssetsTabProps> = ({
// Handle new file upload
const handleFileUpload = async (file: File) => {
// 1. Validate size (Max 10MB)
const MAX_SIZE = 10 * 1024 * 1024;
if (file.size > MAX_SIZE) {
toast.error('File size exceeds the 10MB limit.');
return;
}
// 2. Validate type
const allowedExtensions = [
'jpg', 'jpeg', 'png', 'webp', 'gif', 'svg', 'avif', 'bmp',
'mp4', 'webm', 'mov', 'pdf', 'csv', 'xlsx', 'xls', 'doc', 'docx'
];
const fileExtension = file.name.split('.').pop()?.toLowerCase();
const isAllowedType =
file.type.startsWith('image/') ||
file.type.startsWith('video/') ||
[
'application/pdf', 'text/csv',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel', 'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
].includes(file.type) ||
allowedExtensions.includes(fileExtension || '');
if (!isAllowedType) {
toast.error('Unsupported file format. Please upload images, videos, PDFs, CSVs, or Word/Excel documents.');
return;
}
setUploading(true);
try {
// 1. Upload to PIM media server
@@ -306,21 +336,31 @@ export const ProductAssetsTab: React.FC<ProductAssetsTabProps> = ({
)}
</div>
<div className="bg-surface border border-border rounded-xl p-6 flex flex-col justify-between">
<div className="bg-surface border border-border rounded-xl p-6 flex flex-col justify-between gap-4">
<div>
<h4 className="font-semibold text-foreground text-xs">Asset Library</h4>
<h4 className="font-semibold text-foreground text-xs">Asset Actions</h4>
<p className="text-[11px] text-muted-foreground mt-1">
Select existing images, catalogs or spec documents from the central Asset library.
Upload new files directly or select existing files from the central Asset library.
</p>
</div>
<button
type="button"
onClick={() => setShowPicker(true)}
className="w-full inline-flex items-center justify-center gap-1.5 px-3 py-2 bg-surface border border-border hover:bg-background text-foreground rounded-lg text-xs font-semibold shadow-2xs"
>
<Search className="w-3.5 h-3.5" />
Browse Asset Library
</button>
<div className="space-y-2">
<button
type="button"
onClick={() => fileInputRef.current?.click()}
className="w-full inline-flex items-center justify-center gap-1.5 px-3 py-2 bg-primary hover:bg-primary-hover text-white rounded-lg text-xs font-semibold shadow-2xs cursor-pointer"
>
<Plus className="w-3.5 h-3.5" />
+ Add Asset
</button>
<button
type="button"
onClick={() => setShowPicker(true)}
className="w-full inline-flex items-center justify-center gap-1.5 px-3 py-2 bg-surface border border-border hover:bg-background text-foreground rounded-lg text-xs font-semibold shadow-2xs cursor-pointer"
>
<Search className="w-3.5 h-3.5" />
Browse Library
</button>
</div>
</div>
</div>
)}
@@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { ChevronDown, ChevronUp } from 'lucide-react';
import { ChevronDown, ChevronUp, Plus } from 'lucide-react';
import { DynamicAttributeRenderer } from './DynamicAttributeRenderer';
interface AttributeOption {
@@ -33,6 +33,7 @@ interface ProductAttributeGroupProps {
errors?: Record<string, any>;
touched?: Record<string, any>;
onAttributeChange: (code: string, value: any) => void;
onAddAttributeClick?: (group: AttributeGroup) => void;
readOnly?: boolean;
}
@@ -42,6 +43,7 @@ export const ProductAttributeGroup: React.FC<ProductAttributeGroupProps> = ({
errors = {},
touched = {},
onAttributeChange,
onAddAttributeClick,
readOnly,
}) => {
const [isExpanded, setIsExpanded] = useState(true);
@@ -50,7 +52,22 @@ export const ProductAttributeGroup: React.FC<ProductAttributeGroupProps> = ({
if (attributes.length === 0) {
return (
<div className="bg-surface rounded-xl border border-border shadow-xs p-6">
<h3 className="font-semibold text-foreground mb-4">{group.name}</h3>
<div className="flex items-center justify-between mb-4">
<h3 className="font-semibold text-foreground text-xs uppercase tracking-wider">{group.name}</h3>
{!readOnly && onAddAttributeClick && (
<button
type="button"
onClick={(e) => {
e.stopPropagation();
onAddAttributeClick(group);
}}
className="px-3 py-2 bg-primary hover:bg-primary-hover text-white rounded-lg text-sm font-semibold transition-colors flex items-center justify-center shrink-0 h-[42px] w-[42px]"
title={`Add attribute to ${group.name}`}
>
<Plus className="w-4 h-4" />
</button>
)}
</div>
<div className="text-xs text-muted-foreground italic">No Attributes available.</div>
</div>
);
@@ -58,14 +75,28 @@ export const ProductAttributeGroup: React.FC<ProductAttributeGroupProps> = ({
return (
<div className="bg-surface rounded-xl border border-border shadow-xs overflow-hidden">
<button
type="button"
<div
onClick={() => setIsExpanded(!isExpanded)}
className="w-full flex items-center justify-between px-6 py-4 bg-background/50 border-b border-border/65 hover:bg-background transition-colors"
className="w-full flex items-center justify-between px-6 py-4 bg-background/50 border-b border-border/65 hover:bg-background transition-colors cursor-pointer"
>
<h3 className="font-semibold text-foreground text-xs uppercase tracking-wider">{group.name}</h3>
{isExpanded ? <ChevronUp className="w-4 h-4 text-muted-foreground" /> : <ChevronDown className="w-4 h-4 text-muted-foreground" />}
</button>
<div className="flex items-center gap-3">
{!readOnly && onAddAttributeClick && (
<button
type="button"
onClick={(e) => {
e.stopPropagation();
onAddAttributeClick(group);
}}
className="px-3 py-2 bg-primary hover:bg-primary-hover text-white rounded-lg text-sm font-semibold transition-colors flex items-center justify-center shrink-0 h-[42px] w-[42px]"
title={`Add attribute to ${group.name}`}
>
<Plus className="w-4 h-4" />
</button>
)}
{isExpanded ? <ChevronUp className="w-4 h-4 text-muted-foreground" /> : <ChevronDown className="w-4 h-4 text-muted-foreground" />}
</div>
</div>
{isExpanded && (
<div className="p-6 grid grid-cols-2 gap-6">
File diff suppressed because it is too large Load Diff