2026-07-30 14:38:05 +00:00
|
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
|
|
// components/AddEntityModal.tsx
|
|
|
|
|
|
// Shared modal for adding a new client director or company.
|
|
|
|
|
|
// Opens on "Add Director" / "Add Company" button click.
|
|
|
|
|
|
// On submit: POSTs to /api/pb/records/create, invalidates the
|
|
|
|
|
|
// relevant list query, shows success toast, closes modal.
|
|
|
|
|
|
|
|
|
|
|
|
import { useState, useEffect, useRef } from "react";
|
|
|
|
|
|
import { useQueryClient } from "@tanstack/react-query";
|
|
|
|
|
|
import { pbCreateClient } from "@/lib/api";
|
|
|
|
|
|
import { pbList } from "@/lib/api";
|
|
|
|
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
|
|
/** "director" | "company" */
|
|
|
|
|
|
entity: "director" | "company";
|
|
|
|
|
|
/** Controlled open state (passed from parent) */
|
|
|
|
|
|
open: boolean;
|
|
|
|
|
|
/** Called when modal requests to close (user dismissed or success) */
|
|
|
|
|
|
onClose: () => void;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
interface Director {
|
|
|
|
|
|
id: string;
|
|
|
|
|
|
surname: string;
|
|
|
|
|
|
first_names: string;
|
|
|
|
|
|
id_no: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default function AddEntityModal({ entity, open, onClose }: Props) {
|
|
|
|
|
|
const qc = useQueryClient();
|
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
|
|
const overlayRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
|
|
|
|
|
// Director form state
|
|
|
|
|
|
const [surname, setSurname] = useState("");
|
|
|
|
|
|
const [firstNames, setFirstNames] = useState("");
|
|
|
|
|
|
const [idNo, setIdNo] = useState("");
|
|
|
|
|
|
const [telephone, setTelephone] = useState("");
|
|
|
|
|
|
const [email, setEmail] = useState("");
|
|
|
|
|
|
|
|
|
|
|
|
// Company form state
|
|
|
|
|
|
const [enterpriseNo, setEnterpriseNo] = useState("");
|
|
|
|
|
|
const [enterpriseName, setEnterpriseName] = useState("");
|
|
|
|
|
|
const [enterpriseType, setEnterpriseType] = useState("");
|
|
|
|
|
|
const [registrationDate, setRegistrationDate] = useState("");
|
|
|
|
|
|
const [physicalAddress, setPhysicalAddress] = useState("");
|
|
|
|
|
|
const [postalAddress, setPostalAddress] = useState("");
|
|
|
|
|
|
const [selectedDirectorId, setSelectedDirectorId] = useState("");
|
|
|
|
|
|
|
|
|
|
|
|
// Directors list for company form dropdown
|
|
|
|
|
|
const [directors, setDirectors] = useState<Director[]>([]);
|
|
|
|
|
|
|
|
|
|
|
|
// Reset form whenever modal opens
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (open) {
|
|
|
|
|
|
setSurname(""); setFirstNames(""); setIdNo(""); setTelephone(""); setEmail("");
|
|
|
|
|
|
setEnterpriseNo(""); setEnterpriseName(""); setEnterpriseType("");
|
|
|
|
|
|
setRegistrationDate(""); setPhysicalAddress(""); setPostalAddress("");
|
|
|
|
|
|
setSelectedDirectorId(""); setError(null);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [open]);
|
|
|
|
|
|
|
|
|
|
|
|
// Load directors list when opening the company form
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (open && entity === "company") {
|
|
|
|
|
|
pbList<Director>({
|
|
|
|
|
|
collection: "ysterbaard_directors",
|
|
|
|
|
|
perPage: 500,
|
|
|
|
|
|
sort: "surname",
|
|
|
|
|
|
fields: "id,surname,first_names,id_no",
|
|
|
|
|
|
}).then((r) => setDirectors(r.items)).catch(() => {});
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [open, entity]);
|
|
|
|
|
|
|
|
|
|
|
|
if (!open) return null;
|
|
|
|
|
|
|
|
|
|
|
|
const handleOverlayClick = (e: React.MouseEvent) => {
|
|
|
|
|
|
if (e.target === overlayRef.current) onClose();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const isDirector = entity === "director";
|
|
|
|
|
|
const title = isDirector ? "Add new client director" : "Add new client company";
|
|
|
|
|
|
const subtitle = isDirector
|
|
|
|
|
|
? "Fill in the details. The director will be saved with is_client=true."
|
|
|
|
|
|
: "Fill in the details. The company will be saved with is_client=true.";
|
|
|
|
|
|
|
|
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
setError(null);
|
|
|
|
|
|
setLoading(true);
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (isDirector) {
|
|
|
|
|
|
if (!surname.trim() || !firstNames.trim()) {
|
|
|
|
|
|
setError("Surname and first names are required.");
|
|
|
|
|
|
setLoading(false);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const fields: Record<string, string> = {
|
|
|
|
|
|
surname: surname.trim(),
|
|
|
|
|
|
first_names: firstNames.trim(),
|
|
|
|
|
|
source: "app",
|
|
|
|
|
|
};
|
|
|
|
|
|
if (idNo.trim()) fields.id_no = idNo.trim();
|
|
|
|
|
|
if (telephone.trim()) fields.telephone = telephone.trim();
|
|
|
|
|
|
if (email.trim()) fields.email = email.trim();
|
|
|
|
|
|
await pbCreateClient({ collection: "ysterbaard_directors", fields });
|
|
|
|
|
|
await qc.invalidateQueries({ queryKey: ["pb-list", "ysterbaard_directors"] });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (!enterpriseNo.trim() || !enterpriseName.trim()) {
|
|
|
|
|
|
setError("Enterprise number and name are required.");
|
|
|
|
|
|
setLoading(false);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const fields: Record<string, string> = {
|
|
|
|
|
|
enterprise_no: enterpriseNo.trim().toUpperCase(),
|
|
|
|
|
|
enterprise_name: enterpriseName.trim().toUpperCase(),
|
|
|
|
|
|
source: "app",
|
|
|
|
|
|
};
|
|
|
|
|
|
if (enterpriseType.trim()) fields.enterprise_type = enterpriseType.trim();
|
|
|
|
|
|
if (registrationDate.trim()) fields.registration_date = registrationDate.trim();
|
|
|
|
|
|
if (physicalAddress.trim()) fields.physical_address = physicalAddress.trim();
|
|
|
|
|
|
if (postalAddress.trim()) fields.postal_address = postalAddress.trim();
|
|
|
|
|
|
if (selectedDirectorId) fields.director = selectedDirectorId;
|
|
|
|
|
|
await pbCreateClient({ collection: "ysterbaard_companies", fields });
|
|
|
|
|
|
await qc.invalidateQueries({ queryKey: ["pb-list", "ysterbaard_companies"] });
|
|
|
|
|
|
}
|
|
|
|
|
|
onClose();
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
setError(err instanceof Error ? err.message : "Something went wrong. Please try again.");
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setLoading(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div
|
|
|
|
|
|
ref={overlayRef}
|
|
|
|
|
|
onClick={handleOverlayClick}
|
|
|
|
|
|
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4"
|
|
|
|
|
|
role="dialog"
|
|
|
|
|
|
aria-modal="true"
|
|
|
|
|
|
aria-label={title}
|
|
|
|
|
|
>
|
|
|
|
|
|
<div className="bg-surface border border-border rounded-xl shadow-2xl w-full max-w-lg flex flex-col max-h-[90vh]">
|
|
|
|
|
|
{/* Header */}
|
|
|
|
|
|
<div className="px-6 pt-6 pb-4 border-b border-border flex-shrink-0">
|
|
|
|
|
|
<div className="flex items-start justify-between">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<h2 className="text-lg font-bold text-fg">{title}</h2>
|
|
|
|
|
|
<p className="text-sm text-muted mt-0.5">{subtitle}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
|
className="ml-4 text-muted hover:text-fg text-xl leading-none p-1 rounded transition-colors"
|
|
|
|
|
|
aria-label="Close"
|
|
|
|
|
|
>
|
|
|
|
|
|
×
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Form */}
|
|
|
|
|
|
<form onSubmit={handleSubmit} className="flex-1 overflow-y-auto px-6 py-5 space-y-4">
|
|
|
|
|
|
{error && (
|
|
|
|
|
|
<div className="bg-red-500/10 border border-red-500/30 rounded-lg px-4 py-3 text-sm text-red-400">
|
|
|
|
|
|
{error}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{isDirector ? (
|
|
|
|
|
|
<>
|
|
|
|
|
|
{/* Surname */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-semibold text-fg mb-1.5" htmlFor="surname">
|
|
|
|
|
|
Surname <span className="text-red-400">*</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
id="surname"
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
value={surname}
|
|
|
|
|
|
onChange={(e) => setSurname(e.target.value.toUpperCase())}
|
|
|
|
|
|
className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg placeholder:text-muted focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent"
|
|
|
|
|
|
placeholder="e.g. JONES"
|
|
|
|
|
|
required
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* First names */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-semibold text-fg mb-1.5" htmlFor="firstNames">
|
|
|
|
|
|
First names <span className="text-red-400">*</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
id="firstNames"
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
value={firstNames}
|
|
|
|
|
|
onChange={(e) => setFirstNames(e.target.value.toUpperCase())}
|
|
|
|
|
|
className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg placeholder:text-muted focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent"
|
|
|
|
|
|
placeholder="e.g. PETER JOHANNES"
|
|
|
|
|
|
required
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* ID number */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-semibold text-fg mb-1.5" htmlFor="idNo">
|
|
|
|
|
|
SA ID number <span className="text-xs text-muted font-normal">(optional)</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
id="idNo"
|
2026-07-30 15:53:41 +00:00
|
|
|
|
type="tel"
|
2026-07-30 14:38:05 +00:00
|
|
|
|
value={idNo}
|
|
|
|
|
|
onChange={(e) => setIdNo(e.target.value.replace(/\D/g, "").slice(0, 13))}
|
|
|
|
|
|
className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg placeholder:text-muted focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent font-mono"
|
|
|
|
|
|
placeholder="13 digits"
|
|
|
|
|
|
maxLength={13}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Telephone */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-semibold text-fg mb-1.5" htmlFor="telephone">
|
|
|
|
|
|
Telephone <span className="text-xs text-muted font-normal">(optional)</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
id="telephone"
|
|
|
|
|
|
type="tel"
|
|
|
|
|
|
value={telephone}
|
|
|
|
|
|
onChange={(e) => setTelephone(e.target.value)}
|
|
|
|
|
|
className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg placeholder:text-muted focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent"
|
|
|
|
|
|
placeholder="0821234567"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Email */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-semibold text-fg mb-1.5" htmlFor="email">
|
|
|
|
|
|
Email <span className="text-xs text-muted font-normal">(optional)</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
id="email"
|
|
|
|
|
|
type="email"
|
|
|
|
|
|
value={email}
|
|
|
|
|
|
onChange={(e) => setEmail(e.target.value)}
|
|
|
|
|
|
className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg placeholder:text-muted focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent"
|
|
|
|
|
|
placeholder="director@example.com"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<>
|
|
|
|
|
|
{/* Enterprise number */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-semibold text-fg mb-1.5" htmlFor="enterpriseNo">
|
|
|
|
|
|
Enterprise number <span className="text-red-400">*</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
id="enterpriseNo"
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
value={enterpriseNo}
|
|
|
|
|
|
onChange={(e) => setEnterpriseNo(e.target.value.toUpperCase())}
|
|
|
|
|
|
className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg font-mono placeholder:text-muted focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent"
|
|
|
|
|
|
placeholder="K2022808158"
|
|
|
|
|
|
required
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Enterprise name */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-semibold text-fg mb-1.5" htmlFor="enterpriseName">
|
|
|
|
|
|
Enterprise name <span className="text-red-400">*</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
id="enterpriseName"
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
value={enterpriseName}
|
|
|
|
|
|
onChange={(e) => setEnterpriseName(e.target.value.toUpperCase())}
|
|
|
|
|
|
className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg placeholder:text-muted focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent"
|
|
|
|
|
|
placeholder="ABC TRADING PTY LTD"
|
|
|
|
|
|
required
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Enterprise type */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-semibold text-fg mb-1.5" htmlFor="enterpriseType">
|
|
|
|
|
|
Enterprise type <span className="text-xs text-muted font-normal">(optional)</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
id="enterpriseType"
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
value={enterpriseType}
|
|
|
|
|
|
onChange={(e) => setEnterpriseType(e.target.value)}
|
|
|
|
|
|
className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg placeholder:text-muted focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent"
|
|
|
|
|
|
placeholder="Private Company"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Registration date */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-semibold text-fg mb-1.5" htmlFor="registrationDate">
|
|
|
|
|
|
Registration date <span className="text-xs text-muted font-normal">(optional)</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
id="registrationDate"
|
|
|
|
|
|
type="date"
|
|
|
|
|
|
value={registrationDate}
|
|
|
|
|
|
onChange={(e) => setRegistrationDate(e.target.value)}
|
|
|
|
|
|
className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Physical address */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-semibold text-fg mb-1.5" htmlFor="physicalAddress">
|
|
|
|
|
|
Physical address <span className="text-xs text-muted font-normal">(optional)</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<textarea
|
|
|
|
|
|
id="physicalAddress"
|
|
|
|
|
|
value={physicalAddress}
|
|
|
|
|
|
onChange={(e) => setPhysicalAddress(e.target.value)}
|
|
|
|
|
|
rows={2}
|
|
|
|
|
|
className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg placeholder:text-muted focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent resize-none"
|
|
|
|
|
|
placeholder="123 Main Street, Pretoria, 0001"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Postal address */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-semibold text-fg mb-1.5" htmlFor="postalAddress">
|
|
|
|
|
|
Postal address <span className="text-xs text-muted font-normal">(optional)</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<textarea
|
|
|
|
|
|
id="postalAddress"
|
|
|
|
|
|
value={postalAddress}
|
|
|
|
|
|
onChange={(e) => setPostalAddress(e.target.value)}
|
|
|
|
|
|
rows={2}
|
|
|
|
|
|
className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg placeholder:text-muted focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent resize-none"
|
|
|
|
|
|
placeholder="PO Box 123, Pretoria, 0001"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Linked director dropdown */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-semibold text-fg mb-1.5" htmlFor="directorSelect">
|
|
|
|
|
|
Linked director <span className="text-xs text-muted font-normal">(optional)</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<select
|
|
|
|
|
|
id="directorSelect"
|
|
|
|
|
|
value={selectedDirectorId}
|
|
|
|
|
|
onChange={(e) => setSelectedDirectorId(e.target.value)}
|
|
|
|
|
|
className="w-full rounded-lg border border-border bg-surface-warm px-3 py-2.5 text-sm text-fg focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent"
|
|
|
|
|
|
>
|
|
|
|
|
|
<option value="">— None —</option>
|
|
|
|
|
|
{directors.map((d) => (
|
|
|
|
|
|
<option key={d.id} value={d.id}>
|
|
|
|
|
|
{d.surname}, {d.first_names}
|
|
|
|
|
|
{d.id_no ? ` (${d.id_no})` : ""}
|
|
|
|
|
|
</option>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Submit */}
|
|
|
|
|
|
<div className="pt-2 flex gap-3">
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
|
className="flex-1 px-4 py-2.5 rounded-lg border border-border bg-surface-warm text-sm font-semibold text-fg hover:bg-surface transition-colors"
|
|
|
|
|
|
>
|
|
|
|
|
|
Cancel
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="submit"
|
|
|
|
|
|
disabled={loading}
|
|
|
|
|
|
className="flex-1 px-4 py-2.5 rounded-lg bg-accent text-accent-on text-sm font-bold hover:bg-accent-hover transition-colors disabled:opacity-60 disabled:cursor-not-allowed"
|
|
|
|
|
|
>
|
|
|
|
|
|
{loading ? "Saving..." : "Save as client"}
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|