feat(patients): drop phone/dateOfBirth, name fields optional

Reduced the patient record to the minimum a dental clinic actually needs:
just a code, optional first/last name and free-text notes. Phone and
date-of-birth fields are gone from the UI everywhere — Add form, edit
dialog inside the table, the Bağlantı Bilgileri block on job detail, and
the table column list. The patient list now surfaces 'Notlar' instead.

Backend
  - DB: firstName and lastName columns set to required=false via Appwrite
    MCP (tables_db_update_string_column). Existing rows untouched.
  - schema.ts Patient interface: firstName/lastName now optional, phone
    and dateOfBirth removed from the type entirely. The underlying columns
    are still in the DB so legacy rows aren't broken — we just stop
    referencing them in code.
  - validation/patient.ts: firstName/lastName drop min(1), phone and dob
    fields removed.
  - patient-actions.ts: pickFields no longer reads phone/dob, create and
    update payloads no longer write them.

UI fallbacks
  - PatientsTable: header has 'Notlar' instead of Telefon/Doğum. Ad Soyad
    cell shows the joined name or em-dash. Edit dialog mirrors the same
    simplified form.
  - jobs/[jobId] detail page: when patient row has neither name, the page
    title falls back to 'Hasta {patientCode}' (same as before for jobs
    without a linked patient). The Hasta Bilgileri card now shows Ad Soyad
    and Patient Code side by side, with notes spanning both columns.
This commit is contained in:
kovakmedya
2026-05-21 23:01:52 +03:00
parent 0dea028845
commit ca4ea87d37
6 changed files with 32 additions and 84 deletions
@@ -8,6 +8,7 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { createPatientAction } from "@/lib/appwrite/patient-actions";
import { initialPatientFormState } from "@/lib/appwrite/patient-types";
@@ -48,38 +49,21 @@ export function PatientForm() {
<div className="grid grid-cols-2 gap-3">
<div className="grid gap-2">
<Label htmlFor="firstName">Ad *</Label>
<Input id="firstName" name="firstName" required maxLength={100} />
<Label htmlFor="firstName">Ad</Label>
<Input id="firstName" name="firstName" maxLength={100} />
{state.fieldErrors?.firstName && (
<p className="text-destructive text-xs">{state.fieldErrors.firstName}</p>
)}
</div>
<div className="grid gap-2">
<Label htmlFor="lastName">Soyad *</Label>
<Input id="lastName" name="lastName" required maxLength={100} />
<Label htmlFor="lastName">Soyad</Label>
<Input id="lastName" name="lastName" maxLength={100} />
{state.fieldErrors?.lastName && (
<p className="text-destructive text-xs">{state.fieldErrors.lastName}</p>
)}
</div>
</div>
<div className="grid gap-2">
<Label htmlFor="phone">Telefon</Label>
<Input
id="phone"
name="phone"
type="tel"
maxLength={30}
placeholder="+90 555 123 45 67"
autoComplete="tel"
/>
</div>
<div className="grid gap-2">
<Label htmlFor="dateOfBirth">Doğum Tarihi</Label>
<Input id="dateOfBirth" name="dateOfBirth" type="date" />
</div>
<div className="grid gap-2">
<Label htmlFor="notes">Notlar</Label>
<Textarea
@@ -36,12 +36,6 @@ import {
} from "@/lib/appwrite/patient-types";
import type { Patient } from "@/lib/appwrite/schema";
const dateFormatter = new Intl.DateTimeFormat("tr-TR", {
day: "2-digit",
month: "2-digit",
year: "numeric",
});
export function PatientsTable({ rows }: { rows: Patient[] }) {
if (rows.length === 0) {
return (
@@ -57,8 +51,7 @@ export function PatientsTable({ rows }: { rows: Patient[] }) {
<TableRow>
<TableHead>Kod</TableHead>
<TableHead>Ad Soyad</TableHead>
<TableHead>Telefon</TableHead>
<TableHead>Doğum</TableHead>
<TableHead>Notlar</TableHead>
<TableHead>Durum</TableHead>
<TableHead className="text-right">İşlem</TableHead>
</TableRow>
@@ -92,11 +85,12 @@ function PatientRow({ row }: { row: Patient }) {
<TableRow className={row.archived ? "opacity-60" : ""}>
<TableCell className="font-mono text-xs">{row.patientCode}</TableCell>
<TableCell className="font-medium">
{row.firstName} {row.lastName}
{[row.firstName, row.lastName].filter(Boolean).join(" ") || (
<span className="text-muted-foreground"></span>
)}
</TableCell>
<TableCell className="text-muted-foreground">{row.phone || "—"}</TableCell>
<TableCell className="text-muted-foreground">
{row.dateOfBirth ? dateFormatter.format(new Date(row.dateOfBirth)) : "—"}
<TableCell className="text-muted-foreground max-w-[280px] truncate">
{row.notes || "—"}
</TableCell>
<TableCell>
{row.archived ? (
@@ -170,45 +164,24 @@ function EditPatientDialog({
<input type="hidden" name="patientCode" value={row.patientCode} />
<div className="grid grid-cols-2 gap-3">
<div className="grid gap-2">
<Label htmlFor={`first-${row.$id}`}>Ad *</Label>
<Label htmlFor={`first-${row.$id}`}>Ad</Label>
<Input
id={`first-${row.$id}`}
name="firstName"
defaultValue={row.firstName}
required
defaultValue={row.firstName ?? ""}
maxLength={100}
/>
</div>
<div className="grid gap-2">
<Label htmlFor={`last-${row.$id}`}>Soyad *</Label>
<Label htmlFor={`last-${row.$id}`}>Soyad</Label>
<Input
id={`last-${row.$id}`}
name="lastName"
defaultValue={row.lastName}
required
defaultValue={row.lastName ?? ""}
maxLength={100}
/>
</div>
</div>
<div className="grid gap-2">
<Label htmlFor={`phone-${row.$id}`}>Telefon</Label>
<Input
id={`phone-${row.$id}`}
name="phone"
type="tel"
defaultValue={row.phone ?? ""}
maxLength={30}
/>
</div>
<div className="grid gap-2">
<Label htmlFor={`dob-${row.$id}`}>Doğum Tarihi</Label>
<Input
id={`dob-${row.$id}`}
name="dateOfBirth"
type="date"
defaultValue={row.dateOfBirth ? row.dateOfBirth.slice(0, 10) : ""}
/>
</div>
<div className="grid gap-2">
<Label htmlFor={`notes-${row.$id}`}>Notlar</Label>
<Textarea