Files
citpl_cms_react_express_pos…/src/admin/components/FormFields.jsx
T
sandhiya-hepl 4b8af23f5f first commit
2026-07-14 15:20:26 +05:30

123 lines
3.7 KiB
React

import { useState } from 'react';
import { Upload, Plus, Trash2 } from 'lucide-react';
import { adminApi } from '../api';
export function ImageUpload({ value, onChange, label = 'Image' }) {
const [uploading, setUploading] = useState(false);
const handleUpload = async (e) => {
const file = e.target.files?.[0];
if (!file) return;
setUploading(true);
try {
const { url } = await adminApi.upload(file);
onChange(url);
} catch (err) {
alert(err.message);
} finally {
setUploading(false);
}
};
return (
<div className="form-field">
<label className="form-label">{label}</label>
{value && (
<div className="form-preview">
{value.match(/\.(mp4|webm)$/i) ? (
<video src={value} controls />
) : (
<img src={value} alt="" />
)}
</div>
)}
<input
type="text"
className="form-input"
value={value || ''}
onChange={(e) => onChange(e.target.value)}
placeholder="Paste URL or upload a file below"
/>
<label className="form-upload-btn">
<Upload size={14} />
{uploading ? 'Uploading...' : 'Choose file'}
<input type="file" accept="image/*,video/mp4" onChange={handleUpload} hidden disabled={uploading} />
</label>
</div>
);
}
export function Field({ label, value, onChange, multiline = false, type = 'text' }) {
return (
<div className="form-field">
<label className="form-label">{label}</label>
{multiline ? (
<textarea
className="form-textarea"
value={value || ''}
onChange={(e) => onChange(e.target.value)}
rows={4}
/>
) : (
<input
type={type}
className="form-input"
value={value || ''}
onChange={(e) => onChange(e.target.value)}
/>
)}
</div>
);
}
export function ArrayEditor({ label, items, onChange, fields }) {
const updateItem = (index, key, val) => {
const next = items.map((item, i) => (i === index ? { ...item, [key]: val } : item));
onChange(next);
};
const addItem = () => {
const blank = fields.reduce((acc, f) => ({ ...acc, [f.key]: f.default ?? '' }), { id: Date.now() });
onChange([...items, blank]);
};
const removeItem = (index) => onChange(items.filter((_, i) => i !== index));
return (
<div className="array-section">
<div className="array-header">
<h4 className="array-title">{label}</h4>
<button type="button" onClick={addItem} className="array-add-btn">
<Plus size={14} /> Add item
</button>
</div>
{items.length === 0 && (
<p style={{ color: '#94a3b8', fontSize: '0.85rem', margin: '0 0 1rem' }}>No items yet. Click &quot;Add item&quot; to create one.</p>
)}
{items.map((item, index) => (
<div key={item.id ?? index} className="array-item">
<div className="array-item-header">
<span className="array-item-badge">Item {index + 1}</span>
<button type="button" onClick={() => removeItem(index)} className="array-remove-btn">
<Trash2 size={12} /> Remove
</button>
</div>
{fields.map((f) =>
f.type === 'image' ? (
<ImageUpload key={f.key} label={f.label} value={item[f.key]} onChange={(v) => updateItem(index, f.key, v)} />
) : (
<Field
key={f.key}
label={f.label}
value={item[f.key]}
onChange={(v) => updateItem(index, f.key, v)}
multiline={f.multiline}
/>
)
)}
</div>
))}
</div>
);
}