Files
hihala-dashboard/src/components/Report/ReportForm.tsx
T
2026-04-28 14:47:39 +03:00

171 lines
6.8 KiB
TypeScript

import React, { useRef } from 'react';
import AltMultiSelect from '../shared/AltMultiSelect';
import type { ReportConfig } from './reportHelpers';
interface Props {
config: ReportConfig;
onChange: (patch: Partial<ReportConfig>) => void;
allMuseums: string[];
allChannels: string[];
}
function SectionTitle({ children }: { children: React.ReactNode }) {
return <div className="rf-section-title">{children}</div>;
}
function Field({ label, children }: { label: string; children: React.ReactNode }) {
return (
<label className="rf-field">
<span className="rf-label">{label}</span>
{children}
</label>
);
}
function Toggle({ left, right, value, onChange }: {
left: string; right: string; value: boolean; onChange: (v: boolean) => void;
}) {
return (
<div className="rf-toggle">
<button type="button" className={`rf-toggle-opt${!value ? ' rf-toggle-opt--on' : ''}`} onClick={() => onChange(false)}>{left}</button>
<button type="button" className={`rf-toggle-opt${value ? ' rf-toggle-opt--on' : ''}`} onClick={() => onChange(true)}>{right}</button>
</div>
);
}
function CheckRow({ label, checked, onChange }: { label: string; checked: boolean; onChange: (v: boolean) => void }) {
return (
<label className="rf-check-row">
<input type="checkbox" checked={checked} onChange={e => onChange(e.target.checked)} className="rf-checkbox" />
<span>{label}</span>
</label>
);
}
export default function ReportForm({ config: cfg, onChange, allMuseums, allChannels }: Props) {
const logoInputRef = useRef<HTMLInputElement>(null);
const handleLogoUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
if (file.size > 2 * 1024 * 1024) { alert('Logo must be under 2 MB'); return; }
const reader = new FileReader();
reader.onload = () => onChange({ clientLogoBase64: reader.result as string });
reader.readAsDataURL(file);
};
return (
<div className="report-form">
<SectionTitle>Client Info</SectionTitle>
<Field label="Report title">
<input className="rf-input" type="text" value={cfg.title}
onChange={e => onChange({ title: e.target.value })}
placeholder="Q1 2025 Visitor Performance" />
</Field>
<Field label="Prepared for (company)">
<input className="rf-input" type="text" value={cfg.clientName}
onChange={e => onChange({ clientName: e.target.value })}
placeholder="Acme Group" />
</Field>
<Field label="Contact name (optional)">
<input className="rf-input" type="text" value={cfg.contactName}
onChange={e => onChange({ contactName: e.target.value })}
placeholder="Mohammed Al-..." />
</Field>
<Field label="Client logo (PNG/JPG, max 2 MB)">
<div className="rf-logo-row">
<button type="button" className="rf-upload-btn" onClick={() => logoInputRef.current?.click()}>
{cfg.clientLogoBase64 ? 'Change logo' : 'Upload logo'}
</button>
{cfg.clientLogoBase64 && (
<>
<img src={cfg.clientLogoBase64} alt="preview" className="rf-logo-preview" />
<button type="button" className="rf-remove-btn" onClick={() => onChange({ clientLogoBase64: null })}></button>
</>
)}
<input ref={logoInputRef} type="file" accept="image/png,image/jpeg"
style={{ display: 'none' }} onChange={handleLogoUpload} />
</div>
</Field>
<Field label="Accent color">
<div className="rf-color-row">
<input type="color" value={cfg.accentColor}
onChange={e => onChange({ accentColor: e.target.value })}
className="rf-color-input" />
<span className="rf-color-val">{cfg.accentColor}</span>
</div>
</Field>
<SectionTitle>Data Selection</SectionTitle>
<div className="rf-date-row">
<Field label="Start date">
<input className="rf-input" type="date" value={cfg.startDate}
onChange={e => onChange({ startDate: e.target.value })} />
</Field>
<Field label="End date">
<input className="rf-input" type="date" value={cfg.endDate}
onChange={e => onChange({ endDate: e.target.value })} />
</Field>
</div>
<Field label="Museums">
<AltMultiSelect value={cfg.selectedMuseums} options={allMuseums}
onChange={v => onChange({ selectedMuseums: v })}
allLabel="All museums" countLabel={n => `${n} museums`} clearLabel="Clear" />
</Field>
<Field label="Channels">
<AltMultiSelect value={cfg.selectedChannels} options={allChannels}
onChange={v => onChange({ selectedChannels: v })}
allLabel="All channels" countLabel={n => `${n} channels`} clearLabel="Clear" />
</Field>
<Field label="VAT">
<Toggle left="Excl. VAT" right="Incl. VAT" value={cfg.includeVAT}
onChange={v => onChange({ includeVAT: v })} />
</Field>
<CheckRow label="Include previous year comparison"
checked={cfg.includeComparison} onChange={v => onChange({ includeComparison: v })} />
<SectionTitle>Content Sections</SectionTitle>
<CheckRow label="Executive summary" checked={cfg.showExecutiveSummary} onChange={v => onChange({ showExecutiveSummary: v })} />
<CheckRow label="Key metrics table" checked={cfg.showMetricsTable} onChange={v => onChange({ showMetricsTable: v })} />
<CheckRow label="Revenue trend chart" checked={cfg.showTrendChart} onChange={v => onChange({ showTrendChart: v })} />
<CheckRow label="Breakdown by museum" checked={cfg.showMuseumBreakdown} onChange={v => onChange({ showMuseumBreakdown: v })} />
<CheckRow label="Breakdown by channel" checked={cfg.showChannelBreakdown} onChange={v => onChange({ showChannelBreakdown: v })} />
<CheckRow label="Pilgrim capture rate" checked={cfg.showPilgrimCapture} onChange={v => onChange({ showPilgrimCapture: v })} />
<SectionTitle>Presentation</SectionTitle>
<Field label="Language">
<Toggle left="English" right="العربية" value={cfg.language === 'ar'}
onChange={v => onChange({ language: v ? 'ar' : 'en' })} />
</Field>
<Field label="Orientation">
<Toggle left="Portrait" right="Landscape" value={cfg.orientation === 'landscape'}
onChange={v => onChange({ orientation: v ? 'landscape' : 'portrait' })} />
</Field>
<Field label="Confidentiality">
<select className="rf-input" value={cfg.confidentiality}
onChange={e => onChange({ confidentiality: e.target.value as ReportConfig['confidentiality'] })}>
<option value="Confidential">Confidential</option>
<option value="Internal">Internal</option>
<option value="Public">Public</option>
</select>
</Field>
</div>
);
}