Files
dmail-admin/src/pages/email-builder/components/blocks/ImageBlock.tsx
T
2025-07-15 12:40:39 +03:30

187 lines
6.4 KiB
TypeScript

import { FC, useState } from 'react'
import { ImageBlock as ImageBlockType } from '../../types/blocks'
import Input from '@/components/Input'
import UploadBoxDraggble from '@/components/UploadBoxDraggble'
interface ImageBlockProps {
block: ImageBlockType
isSelected?: boolean
onUpdate: (updates: Partial<ImageBlockType>) => void
onSelect: () => void
isEditing?: boolean
}
const ImageBlock: FC<ImageBlockProps> = ({
block,
isSelected,
onUpdate,
onSelect,
isEditing = false
}) => {
const [localSrc, setLocalSrc] = useState(block.data.src)
const [localAlt, setLocalAlt] = useState(block.data.alt)
const [localUrl, setLocalUrl] = useState(block.data.url || '')
const handleSrcChange = (src: string) => {
setLocalSrc(src)
onUpdate({
data: {
...block.data,
src
}
})
}
const handleAltChange = (alt: string) => {
setLocalAlt(alt)
onUpdate({
data: {
...block.data,
alt
}
})
}
const handleUrlChange = (url: string) => {
setLocalUrl(url)
onUpdate({
data: {
...block.data,
url
}
})
}
const handleImageUpload = (files: File[]) => {
if (files.length > 0) {
const file = files[0]
const imageUrl = URL.createObjectURL(file)
handleSrcChange(imageUrl)
}
}
const imageStyle = {
width: typeof block.style.width === 'number' ? `${block.style.width}px` : block.style.width,
height: typeof block.style.height === 'number' ? `${block.style.height}px` : block.style.height,
objectFit: block.style.objectFit as 'cover' | 'contain' | 'fill',
borderRadius: block.style.borderRadius ? `${block.style.borderRadius}px` : '0',
maxWidth: '100%',
display: 'block',
margin: block.style.margin ?
`${block.style.margin.top}px ${block.style.margin.right}px ${block.style.margin.bottom}px ${block.style.margin.left}px` :
'8px 0'
}
const containerStyle = {
border: isSelected ? '2px dashed #0038FF' : '2px dashed transparent',
borderRadius: '8px',
padding: '4px',
textAlign: block.style.textAlign as 'left' | 'center' | 'right',
position: 'relative' as const,
display: 'inline-block',
minHeight: '60px',
minWidth: '80px'
}
// Process variables in src for preview
const processVariables = (content: string) => {
return content.replace(/\{\{(\w+)\}\}/g, (match, key) => {
const sampleData: Record<string, string> = {
userImage: 'https://via.placeholder.com/150x150?text=تصویر+کاربر',
companyLogo: 'https://via.placeholder.com/200x80?text=لوگو+شرکت',
productImage: 'https://via.placeholder.com/300x200?text=تصویر+محصول'
}
return sampleData[key] || match
})
}
const processedSrc = processVariables(localSrc)
return (
<div
style={containerStyle}
onClick={onSelect}
className="image-block-wrapper"
>
{isEditing ? (
<div className="space-y-3 p-2 bg-gray-50 rounded">
<UploadBoxDraggble
label="آپلود تصویر"
onChange={handleImageUpload}
/>
<Input
label="آدرس تصویر"
value={localSrc}
onChange={(e) => handleSrcChange(e.target.value)}
placeholder="https://example.com/image.jpg"
/>
<Input
label="متن جایگزین (Alt Text)"
value={localAlt}
onChange={(e) => handleAltChange(e.target.value)}
placeholder="توضیح تصویر"
/>
<Input
label="لینک تصویر (اختیاری)"
value={localUrl}
onChange={(e) => handleUrlChange(e.target.value)}
placeholder="https://example.com"
/>
</div>
) : (
<div>
{localUrl ? (
<a
href={localUrl}
target="_blank"
rel="noopener noreferrer"
onClick={(e) => e.stopPropagation()}
>
<img
src={processedSrc}
alt={localAlt}
style={imageStyle}
onError={(e) => {
const target = e.target as HTMLImageElement
target.src = 'https://via.placeholder.com/400x200?text=تصویر+یافت+نشد'
}}
/>
</a>
) : (
<img
src={processedSrc}
alt={localAlt}
style={imageStyle}
onError={(e) => {
const target = e.target as HTMLImageElement
target.src = 'https://via.placeholder.com/400x200?text=تصویر+یافت+نشد'
}}
/>
)}
</div>
)}
{/* Block type indicator */}
{isSelected && (
<div
style={{
position: 'absolute',
top: '-8px',
right: '8px',
backgroundColor: '#0038FF',
color: 'white',
padding: '2px 6px',
fontSize: '10px',
borderRadius: '4px',
fontWeight: 'bold',
zIndex: 10
}}
>
تصویر
</div>
)}
</div>
)
}
export default ImageBlock