UNPKG

@megaads/wm

Version:

To install the library, use npm:

236 lines (217 loc) 7.12 kB
import React, { useMemo } from 'react'; export default function OptionsPanel({ snapshot, service, onSnapshot }) { if (!snapshot) return null; const apply = (snap) => onSnapshot(snap); return ( <div> <TemplatePicker groups={snapshot.templateOptions} onPick={(tpl) => apply(service.selectTemplate(tpl.id))} /> <div className="section"> <h3>Layer options ({snapshot.layerOptions.length})</h3> {snapshot.layerOptions.length === 0 && ( <div style={{ color: '#94a3b8', fontSize: 12, padding: 8, background: '#1e293b', borderRadius: 4 }}> {snapshot.template ? `Template "${snapshot.template.name}" không có layer interactive nào (không có layer nào có form_label). Đây là template tĩnh — thử chọn template khác.` : 'Chưa chọn template. Pick một template phía trên để bắt đầu.'} </div> )} {snapshot.layerOptions.map((layer) => ( <LayerControl key={layer.id} layer={layer} service={service} onSnapshot={apply} errors={snapshot.validation.errors} /> ))} </div> </div> ); } function TemplatePicker({ groups, onPick }) { if (!groups || groups.length === 0) return null; return ( <> {groups.map((group) => ( <div className="section" key={group.artworkId}> <h3>{group.label}</h3> <div className="template-grid"> {group.optionValues.map((tpl) => ( <div key={tpl.id} className={'template-tile' + (tpl.active ? ' active' : '')} onClick={() => onPick(tpl)} > {tpl.thumbnail && <img src={tpl.thumbnail} alt={tpl.name} />} <div className="name">{tpl.name}</div> </div> ))} </div> </div> ))} </> ); } function LayerControl({ layer, service, onSnapshot, errors }) { const error = errors.find((e) => e.type === 'layer' && e.layerId === layer.id); return ( <div className="layer-control"> <div className="label"> <span> {layer.form_label || layer.name || layer.id} {layer.required && <span className="required">*</span>} </span> <span className="badge">{layer.input_type}</span> </div> {layer.form_visibility && ( <div className="checkbox-row"> <input id={`vis-${layer.id}`} type="checkbox" checked={layer.form_visibility_value !== false} onChange={(e) => onSnapshot(service.changeLayerVisibility(layer, e.target.checked)) } /> <label htmlFor={`vis-${layer.id}`} style={{ fontSize: 12 }}> Show layer </label> </div> )} <ControlBody layer={layer} service={service} onSnapshot={onSnapshot} /> {error && <div className="error-box">{error.message}</div>} </div> ); } function ControlBody({ layer, service, onSnapshot }) { switch (layer.input_type) { case 'text': return <TextControl layer={layer} service={service} onSnapshot={onSnapshot} />; case 'photo': return <PhotoControl layer={layer} service={service} onSnapshot={onSnapshot} />; case 'option': case 'clipart': return <OptionGrid layer={layer} service={service} onSnapshot={onSnapshot} />; case 'grouped_clipart': return <GroupedClipartControl layer={layer} service={service} onSnapshot={onSnapshot} />; default: return ( <div style={{ fontSize: 12, color: '#64748b' }}> Unsupported input_type: {layer.input_type} </div> ); } } function TextControl({ layer, service, onSnapshot }) { return ( <input type="text" value={layer.value || ''} maxLength={layer.max_length || undefined} placeholder={layer.text || ''} onChange={(e) => onSnapshot(service.changeInputValue(layer, e.target.value))} /> ); } function PhotoControl({ layer, service, onSnapshot }) { const onPick = (e) => { const file = e.target.files?.[0]; if (!file) return; const url = URL.createObjectURL(file); onSnapshot(service.changeUploadValue(layer, url, { file })); }; return ( <div> {layer.show_value && ( <img src={layer.show_value} alt="" style={{ maxWidth: '100%', maxHeight: 100, border: '1px solid #334155', borderRadius: 4, marginBottom: 6, }} /> )} <input type="file" accept="image/*" onChange={onPick} style={{ fontSize: 12 }} /> </div> ); } function OptionGrid({ layer, service, onSnapshot }) { const items = layer.option_items || []; if (items.length === 0) { return <div style={{ fontSize: 12, color: '#64748b' }}>(no items)</div>; } return ( <div className="option-grid"> {items.map((item) => ( <div key={item.id} className={'option-tile' + (item.active ? ' active' : '')} onClick={() => onSnapshot(service.changeLayerOptionValue(item, layer))} title={item.name} > {item.url || item.thumbnail ? ( <img src={item.thumbnail || item.url} alt={item.name} /> ) : ( <span className="label-text">{item.name}</span> )} </div> ))} </div> ); } function GroupedClipartControl({ layer, service, onSnapshot }) { const groups = layer.option_items || []; const activeGroup = useMemo( () => groups.find((g) => g.active) || groups[0] || null, [groups] ); if (!groups.length) { return <div style={{ fontSize: 12, color: '#64748b' }}>(no groups)</div>; } return ( <div> <div className="group-tabs"> {groups.map((group) => ( <div key={group.id} className={'group-tab' + (group.active ? ' active' : '')} onClick={() => onSnapshot(service.changeOptionGroupClipartValue(group, layer))} title={group.name} > {group.thumbnail ? ( <img src={group.thumbnail} alt={group.name} /> ) : ( <span className="name">{group.name}</span> )} </div> ))} </div> {activeGroup && ( <div className="option-grid"> {(activeGroup.options || []).map((item) => ( <div key={item.id} className={'option-tile' + (item.active ? ' active' : '')} onClick={() => onSnapshot(service.changeLayerOptionValue(item, activeGroup, layer)) } title={item.name} > {item.url || item.thumbnail ? ( <img src={item.thumbnail || item.url} alt={item.name} /> ) : ( <span className="label-text">{item.name}</span> )} </div> ))} </div> )} </div> ); }