268 lines
12 KiB
TypeScript
268 lines
12 KiB
TypeScript
import { Form, Head } from '@inertiajs/react';
|
|
import { ExternalLink, MapPin, Pencil, Plus, Trash2 } from 'lucide-react';
|
|
import type { ReactNode } from 'react';
|
|
import {
|
|
ConfirmDelete,
|
|
FormDialog,
|
|
FormField,
|
|
PageHeader,
|
|
} from '@/components/admin/form-controls';
|
|
import Heading from '@/components/heading';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import { officeAddress } from '@/data/site';
|
|
import { edit } from '@/routes/admin/company';
|
|
import { update as updateContact } from '@/routes/admin/company/contact';
|
|
import { destroy, store, update } from '@/routes/admin/offices';
|
|
import type { Office, SiteInfo } from '@/types';
|
|
|
|
export default function CompanyEdit({ contact, offices }: SiteInfo) {
|
|
return (
|
|
<>
|
|
<Head title="Info Perusahaan" />
|
|
<div className="flex flex-col gap-8 p-4 md:p-6">
|
|
<PageHeader
|
|
title="Info Perusahaan"
|
|
description="Kontak dan alamat kantor yang tampil di header, footer, dan halaman Kontak."
|
|
/>
|
|
|
|
<section className="bg-card flex flex-col gap-6 rounded-xl border p-5">
|
|
<Heading
|
|
variant="small"
|
|
title="Kontak"
|
|
description="Email busdev juga menjadi tujuan notifikasi konsultasi baru."
|
|
/>
|
|
<Form
|
|
{...updateContact.form()}
|
|
options={{ preserveScroll: true }}
|
|
className="grid gap-4 sm:grid-cols-2"
|
|
>
|
|
{({ processing, errors }) => (
|
|
<>
|
|
<FormField
|
|
id="phone"
|
|
label="Telepon kantor"
|
|
error={errors.phone}
|
|
>
|
|
<Input
|
|
id="phone"
|
|
name="phone"
|
|
defaultValue={contact.phone}
|
|
required
|
|
/>
|
|
</FormField>
|
|
<FormField
|
|
id="whatsapp"
|
|
label="WhatsApp konsultasi"
|
|
error={errors.whatsapp}
|
|
>
|
|
<Input
|
|
id="whatsapp"
|
|
name="whatsapp"
|
|
defaultValue={contact.whatsapp}
|
|
required
|
|
/>
|
|
</FormField>
|
|
<FormField
|
|
id="email_busdev"
|
|
label="Email business development"
|
|
error={errors.email_busdev}
|
|
>
|
|
<Input
|
|
id="email_busdev"
|
|
name="email_busdev"
|
|
type="email"
|
|
defaultValue={contact.email_busdev}
|
|
required
|
|
/>
|
|
</FormField>
|
|
<FormField
|
|
id="email_support"
|
|
label="Email support"
|
|
error={errors.email_support}
|
|
>
|
|
<Input
|
|
id="email_support"
|
|
name="email_support"
|
|
type="email"
|
|
defaultValue={contact.email_support}
|
|
required
|
|
/>
|
|
</FormField>
|
|
<div className="flex justify-end sm:col-span-2">
|
|
<Button type="submit" disabled={processing}>
|
|
Simpan Kontak
|
|
</Button>
|
|
</div>
|
|
</>
|
|
)}
|
|
</Form>
|
|
</section>
|
|
|
|
<section className="flex flex-col gap-4">
|
|
<div className="flex items-end justify-between gap-3">
|
|
<Heading
|
|
variant="small"
|
|
title="Kantor"
|
|
description="Diurutkan berdasarkan nomor urut."
|
|
/>
|
|
<OfficeDialog
|
|
nextOrder={offices.length + 1}
|
|
trigger={
|
|
<Button>
|
|
<Plus /> Tambah Kantor
|
|
</Button>
|
|
}
|
|
/>
|
|
</div>
|
|
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
{offices.map((office) => (
|
|
<div
|
|
key={office.id}
|
|
className="bg-card flex flex-col gap-3 rounded-xl border p-5"
|
|
>
|
|
<div className="flex items-start justify-between gap-2">
|
|
<div className="flex flex-col">
|
|
<span className="font-display font-bold">
|
|
{office.name}
|
|
</span>
|
|
<span className="text-muted-foreground text-xs">
|
|
{office.district} · {office.phone}
|
|
</span>
|
|
</div>
|
|
<div className="flex gap-1">
|
|
<OfficeDialog
|
|
office={office}
|
|
trigger={
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
aria-label="Ubah"
|
|
>
|
|
<Pencil />
|
|
</Button>
|
|
}
|
|
/>
|
|
<ConfirmDelete
|
|
title="Hapus kantor ini?"
|
|
description={`${office.name} tidak akan tampil lagi di website.`}
|
|
form={destroy.form(office.id)}
|
|
trigger={
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
aria-label="Hapus"
|
|
className="text-destructive"
|
|
>
|
|
<Trash2 />
|
|
</Button>
|
|
}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<p className="flex gap-2 text-sm">
|
|
<MapPin className="text-primary mt-0.5 size-4 shrink-0" />
|
|
{officeAddress(office)}
|
|
</p>
|
|
{office.maps_url && (
|
|
<a
|
|
href={office.maps_url}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="text-primary flex items-center gap-1 text-xs font-semibold hover:underline"
|
|
>
|
|
Buka di Google Maps
|
|
<ExternalLink className="size-3.5" />
|
|
</a>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
function OfficeDialog({
|
|
office,
|
|
nextOrder = 1,
|
|
trigger,
|
|
}: {
|
|
office?: Office;
|
|
nextOrder?: number;
|
|
trigger: ReactNode;
|
|
}) {
|
|
const id = (field: string) => `office-${office?.id ?? 'new'}-${field}`;
|
|
const text = (
|
|
field: keyof Office,
|
|
label: string,
|
|
errors: Partial<Record<string, string>>,
|
|
extra: { placeholder?: string; required?: boolean } = {
|
|
required: true,
|
|
},
|
|
) => (
|
|
<FormField id={id(field)} label={label} error={errors[field]}>
|
|
<Input
|
|
id={id(field)}
|
|
name={field}
|
|
defaultValue={office?.[field] ?? ''}
|
|
{...extra}
|
|
/>
|
|
</FormField>
|
|
);
|
|
|
|
return (
|
|
<FormDialog
|
|
trigger={trigger}
|
|
title={office ? 'Ubah Kantor' : 'Tambah Kantor'}
|
|
form={office ? update.form(office.id) : store.form()}
|
|
>
|
|
{(errors) => (
|
|
<>
|
|
{text('name', 'Nama kantor', errors)}
|
|
{text('building', 'Gedung / nomor', errors)}
|
|
{text('street', 'Jalan', errors)}
|
|
<div className="grid gap-4 sm:grid-cols-2">
|
|
{text('area', 'Kelurahan / kecamatan', errors)}
|
|
{text('city', 'Kota & kode pos', errors)}
|
|
{text('district', 'Label wilayah', errors, {
|
|
placeholder: 'Mis. Bintaro',
|
|
required: true,
|
|
})}
|
|
{text('phone', 'Telepon', errors)}
|
|
</div>
|
|
{text('maps_url', 'Link Google Maps (opsional)', errors, {
|
|
placeholder: 'https://maps.app.goo.gl/…',
|
|
})}
|
|
<div className="grid gap-4 sm:grid-cols-2">
|
|
{text('icon', 'Ikon (Material Symbols)', errors, {
|
|
placeholder: 'apartment',
|
|
required: true,
|
|
})}
|
|
<FormField
|
|
id={id('sort_order')}
|
|
label="Nomor urut"
|
|
error={errors.sort_order}
|
|
>
|
|
<Input
|
|
id={id('sort_order')}
|
|
name="sort_order"
|
|
type="number"
|
|
min={0}
|
|
defaultValue={office?.sort_order ?? nextOrder}
|
|
required
|
|
/>
|
|
</FormField>
|
|
</div>
|
|
</>
|
|
)}
|
|
</FormDialog>
|
|
);
|
|
}
|
|
|
|
CompanyEdit.layout = {
|
|
breadcrumbs: [{ title: 'Info Perusahaan', href: edit() }],
|
|
};
|