@@ -0,0 +1,267 @@
|
||||
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() }],
|
||||
};
|
||||
Reference in New Issue
Block a user