194 lines
7.5 KiB
TypeScript
194 lines
7.5 KiB
TypeScript
export type OfferParticulars = {
|
|
business?: Record<string, string | number | null> | null;
|
|
property?: Record<string, string | number | string[] | null> | null;
|
|
};
|
|
const control = 'w-full min-w-0 rounded-md border p-2';
|
|
const propertyLabels: Record<string, string> = {
|
|
house: 'Casa',
|
|
apartment: 'Apartamento',
|
|
office: 'Escritório',
|
|
retail: 'Espaço comercial',
|
|
warehouse: 'Armazém',
|
|
hospitality: 'Hotelaria',
|
|
industrial: 'Industrial',
|
|
mixed_use: 'Uso misto',
|
|
development: 'Empreendimento',
|
|
other: 'Outro',
|
|
};
|
|
|
|
export default function OfferParticularsFields({
|
|
value,
|
|
category,
|
|
sectors,
|
|
propertyTypes,
|
|
disabled,
|
|
onChange,
|
|
}: {
|
|
value: OfferParticulars;
|
|
category: string;
|
|
sectors: { id: number; name: string }[];
|
|
propertyTypes: string[];
|
|
disabled: boolean;
|
|
onChange: (next: OfferParticulars) => void;
|
|
}) {
|
|
if (!['business_sale', 'real_estate'].includes(category)) return null;
|
|
const business = category === 'business_sale';
|
|
const group = business ? 'business' : 'property';
|
|
const data = value[group] ?? {};
|
|
const update = (key: string, next: string | string[] | null) =>
|
|
onChange({ ...value, [group]: { ...data, [key]: next } });
|
|
const text = (key: string, label: string, numeric = false) => (
|
|
<label key={key} className="space-y-1">
|
|
{label}
|
|
<input
|
|
className={control}
|
|
value={String(data[key] ?? '')}
|
|
inputMode={numeric ? 'decimal' : 'text'}
|
|
maxLength={numeric ? 30 : 1000}
|
|
onChange={(e) => update(key, e.target.value || null)}
|
|
/>
|
|
</label>
|
|
);
|
|
const select = (
|
|
key: string,
|
|
label: string,
|
|
options: { value: string; label: string }[],
|
|
) => (
|
|
<label key={key} className="space-y-1">
|
|
{label}
|
|
<select
|
|
className={control}
|
|
value={String(data[key] ?? '')}
|
|
onChange={(e) => update(key, e.target.value || null)}
|
|
>
|
|
<option value="">Por indicar</option>
|
|
{options.map((item) => (
|
|
<option key={item.value} value={item.value}>
|
|
{item.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
);
|
|
return (
|
|
<fieldset
|
|
disabled={disabled}
|
|
className="space-y-4 rounded-lg border p-4"
|
|
>
|
|
<legend className="px-2 font-semibold">
|
|
{business
|
|
? 'Dados da empresa — acesso reservado'
|
|
: 'Características do imóvel'}
|
|
</legend>
|
|
<p className="text-sm">
|
|
Campos opcionais durante a preparação. A gravação não publica
|
|
estes dados.
|
|
</p>
|
|
<div className="grid min-w-0 gap-4 sm:grid-cols-2">
|
|
{business ? (
|
|
<>
|
|
{['sector_id', 'secondary_sector_id'].map(
|
|
(key, index) =>
|
|
select(
|
|
key,
|
|
index
|
|
? 'Sector secundário'
|
|
: 'Sector principal',
|
|
sectors.map((sector) => ({
|
|
value: String(sector.id),
|
|
label: sector.name,
|
|
})),
|
|
),
|
|
)}
|
|
{text('revenue', 'Receita resumida', true)}
|
|
{text(
|
|
'cash_flow',
|
|
'Lucro ou fluxo de caixa resumido',
|
|
true,
|
|
)}
|
|
{select('currency', 'Moeda dos valores da empresa', [
|
|
{ value: 'MZN', label: 'MZN' },
|
|
{ value: 'USD', label: 'USD' },
|
|
])}
|
|
{text('reason', 'Motivo da venda')}
|
|
</>
|
|
) : (
|
|
<>
|
|
{select('transaction_type', 'Tipo de negócio', [
|
|
{ value: 'sale', label: 'Venda' },
|
|
{ value: 'lease', label: 'Arrendamento' },
|
|
])}
|
|
{select(
|
|
'property_type',
|
|
'Tipo de imóvel',
|
|
propertyTypes.map((type) => ({
|
|
value: type,
|
|
label: propertyLabels[type] ?? type,
|
|
})),
|
|
)}
|
|
{text('land_area', 'Área do terreno', true)}
|
|
{text('built_area', 'Área construída', true)}
|
|
{select('area_unit', 'Unidade da área', [
|
|
{ value: 'sqm', label: 'm²' },
|
|
{ value: 'ha', label: 'ha' },
|
|
{ value: 'sqkm', label: 'km²' },
|
|
])}
|
|
{[
|
|
'house',
|
|
'apartment',
|
|
'hospitality',
|
|
'mixed_use',
|
|
].includes(String(data.property_type)) && (
|
|
<>
|
|
{text('bedrooms', 'Quartos', true)}
|
|
{text('bathrooms', 'Casas de banho', true)}
|
|
</>
|
|
)}
|
|
<label>
|
|
Características e comodidades (uma por linha)
|
|
<textarea
|
|
className={control}
|
|
value={
|
|
Array.isArray(data.amenities)
|
|
? data.amenities.join('\n')
|
|
: ''
|
|
}
|
|
onChange={(e) =>
|
|
update(
|
|
'amenities',
|
|
e.target.value
|
|
.split('\n')
|
|
.filter(Boolean),
|
|
)
|
|
}
|
|
/>
|
|
</label>
|
|
</>
|
|
)}
|
|
{select('availability', 'Disponibilidade declarada', [
|
|
{ value: 'available', label: 'Disponível' },
|
|
{ value: 'sold', label: 'Vendido' },
|
|
...(!business
|
|
? [{ value: 'leased', label: 'Arrendado' }]
|
|
: []),
|
|
])}
|
|
</div>
|
|
{value[business ? 'property' : 'business'] && (
|
|
<button
|
|
type="button"
|
|
className="underline"
|
|
onClick={() =>
|
|
onChange({
|
|
...value,
|
|
[business ? 'property' : 'business']: null,
|
|
})
|
|
}
|
|
>
|
|
Retirar os dados do tipo anterior antes de guardar esta
|
|
categoria
|
|
</button>
|
|
)}
|
|
</fieldset>
|
|
);
|
|
}
|